[
  {
    "path": ".dockerignore",
    "content": "docs/\noutrun/\ntmp/\nbin/\n*.tar.gz\nopen-falcon\n"
  },
  {
    "path": ".gitignore",
    "content": "bin/\nout/\n*.swp\n*.swo\n*.tar.gz\ndocs/_site\n.idea\nopen-falcon\nbuild"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: required\n\nlanguage: go\n\narch:\n  - amd64\n  - arm64\ngo:\n  - \"1.15\"\n\nenv:\n  - DB_USER=root DB_PASSWORD=test123456 DB_HOST=127.0.0.1 DB_PORT=13306 REDIS_HOST=127.0.0.1 REDIS_PORT=16379 API_PORT=18080 API_HOST=127.0.0.1\n\nservices:\n  - docker\n\nbefore_install:\n  - tmpdaemon=$(mktemp)\n  - sudo jq '.\"registry-mirrors\" += [\"https://mirror.gcr.io\"]' /etc/docker/daemon.json > $tmpdaemon\n  - sudo mv $tmpdaemon /etc/docker/daemon.json\n  - sudo systemctl daemon-reload\n  - sudo systemctl restart docker\n  - docker system info\n\nscript:\n  - go get -u github.com/go-sql-driver/mysql\n  - make fmt\n  - make fmt-check\n  - make misspell-check\n  - make all\n  - bash ./docker_test.sh\n\nafter_success:\n  - go test -race -coverprofile=coverage.txt -covermode=atomic github.com/open-falcon/falcon-plus/modules/api/test\n  - bash <(curl -s https://codecov.io/bash)\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## 1. Purpose\n\nA primary goal of Open-Falcon is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof).\n\nThis code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior.\n\nWe invite all those who participate in Open-Falcon to help us create safe and positive experiences for everyone.\n\n## 2. Open Source Citizenship\n\nA supplemental goal of this Code of Conduct is to increase open source citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community.\n\nCommunities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society.\n\nIf you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know.\n\n## 3. Expected Behavior\n\nThe following behaviors are expected and requested of all community members:\n\n*   Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community.\n*   Exercise consideration and respect in your speech and actions.\n*   Attempt collaboration before conflict.\n*   Refrain from demeaning, discriminatory, or harassing behavior and speech.\n*   Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential.\n*   Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations.\n\n## 4. Unacceptable Behavior\n\nThe following behaviors are considered harassment and are unacceptable within our community:\n\n*   Violence, threats of violence or violent language directed against another person.\n*   Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language.\n*   Posting or displaying sexually explicit or violent material.\n*   Posting or threatening to post other people’s personally identifying information (\"doxing\").\n*   Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability.\n*   Inappropriate photography or recording.\n*   Inappropriate physical contact. You should have someone’s consent before touching them.\n*   Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances.\n*   Deliberate intimidation, stalking or following (online or in person).\n*   Advocating for, or encouraging, any of the above behavior.\n*   Sustained disruption of community events, including talks and presentations.\n\n## 5. Consequences of Unacceptable Behavior\n\nUnacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated.\n\nAnyone asked to stop unacceptable behavior is expected to comply immediately.\n\nIf a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event).\n\n## 6. Reporting Guidelines\n\nIf you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible. root@open-falcon.com.\n\n\n\nAdditionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress.\n\n## 7. Addressing Grievances\n\nIf you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify Open Falcon with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies.\n\n\n\n## 8. Scope\n\nWe expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venues–online and in-person–as well as in all one-on-one communications pertaining to community business.\n\nThis code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members.\n\n## 9. Contact info\n\nroot@open-falcon.com\n\n## 10. License and attribution\n\nThis Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/).\n\nPortions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy).\n\nRetrieved on November 22, 2016 from [http://citizencodeofconduct.org/](http://citizencodeofconduct.org/)\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "### COMMUNITY\nOpen-Falcon is developed in the open. Here are some of the channels we use to communicate and contribute:\n\n**Mailing lists:**\n- [openfalcon-users](https://groups.google.com/forum/#!forum/openfalcon-users) – for discussions around openfalcon usage and community support\n- [openfalcon-developers](https://groups.google.com/forum/#!forum/openfalcon-developers) – for discussions around openfalcon development\n\n**Issue tracker:** \n- Use the GitHub issue tracker for the various [Open-Falcon repositories](http://github.com/open-falcon) to file bugs and features request. If you need support, please send your questions to the [openfalcon-users](https://groups.google.com/forum/#!forum/openfalcon-users) mailing list rather than filing a GitHub issue.\n\n*Please do not ask individual project members for support. Use the channels above instead, where the whole community can help you and benefit from the solutions provided. If community support is insufficient for your situation, please refer to the Commercial Support section below.*\n\n### CONTRIBUTING\nWe welcome community contributions! Open-Falcon uses GitHub to manage reviews of pull requests.\n\n- If you have a trivial fix or improvement, go ahead and create a pull request, addressing (with `@...`) the maintainer of this repository in the description of the pull request.\n- If you plan to do something more involved, first discuss your ideas on our [mailing list](https://groups.google.com/forum/#!forum/openfalcon-developers). This will avoid unnecessary work and surely give you and us a good deal of inspiration.\n"
  },
  {
    "path": "Dockerfile",
    "content": "# Build container;\nFROM openfalcon/makegcc-golang:1.15-alpine\nLABEL maintainer laiwei.ustc@gmail.com\nUSER root\n\nENV FALCON_DIR=/open-falcon PROJ_PATH=${GOPATH}/src/github.com/open-falcon/falcon-plus\n\nRUN mkdir -p $FALCON_DIR && \\\n    mkdir -p $FALCON_DIR/logs && \\\n    apk add --no-cache ca-certificates bash git supervisor\nCOPY . ${PROJ_PATH}\n\nWORKDIR ${PROJ_PATH}\nRUN make all \\\n    && make pack4docker \\\n    && tar -zxf open-falcon-v*.tar.gz -C ${FALCON_DIR} \\\n    && rm -rf ${PROJ_PATH}\n\n# Final container;\nFROM alpine:3.13\nLABEL maintainer laiwei.ustc@gmail.com\nUSER root\n\nENV FALCON_DIR=/open-falcon\n\nRUN mkdir -p $FALCON_DIR/logs && \\\n    apk add --no-cache ca-certificates bash git supervisor\n\nADD docker/supervisord.conf /etc/supervisord.conf\n\nCOPY --from=0 ${FALCON_DIR} ${FALCON_DIR}\n\nEXPOSE 8433 8080\nWORKDIR ${FALCON_DIR}\n\nCMD [\"/usr/bin/supervisord\", \"-c\", \"/etc/supervisord.conf\"]\n"
  },
  {
    "path": "Dockerfile.module",
    "content": "# Build container;\nFROM openfalcon/makegcc-golang:1.15-alpine\nLABEL maintainer laiwei.ustc@gmail.com\nUSER root\n\nENV FALCON_DIR=/open-falcon PROJ_PATH=${GOPATH}/src/github.com/open-falcon/falcon-plus\n\nRUN mkdir -p $FALCON_DIR && \\\n    apk add --no-cache ca-certificates git\n\nCOPY . ${PROJ_PATH}\n\nWORKDIR ${PROJ_PATH}\n\nARG MODULE\n\nRUN make $MODULE \\\n    && make pack4docker CMD=$MODULE \\\n    && tar -zxf open-falcon-v*.tar.gz -C ${FALCON_DIR} \\\n    && rm -rf ${PROJ_PATH}\n\n# Final container;\nFROM alpine:3.13\nLABEL maintainer laiwei.ustc@gmail.com\nUSER root\n\nENV FALCON_DIR=/open-falcon\n\nRUN mkdir -p $FALCON_DIR/logs && \\\n    apk update && \\\n    apk add --no-cache ca-certificates bash git iproute2\n\nCOPY --from=0 ${FALCON_DIR} ${FALCON_DIR}\n\nEXPOSE 8433 8080\nWORKDIR ${FALCON_DIR}\n"
  },
  {
    "path": "Dockerfile_arm64",
    "content": "FROM jimmytinsley/makegcc-golang\nLABEL maintainer laiwei.ustc@gmail.com\nUSER root\n\nENV FALCON_DIR=/open-falcon PROJ_PATH=${GOPATH}/src/github.com/open-falcon/falcon-plus\n\nRUN mkdir -p $FALCON_DIR && \\\n    mkdir -p $FALCON_DIR/logs && \\\n    apk add --no-cache ca-certificates bash git supervisor\nCOPY . ${PROJ_PATH}\n\nWORKDIR ${PROJ_PATH}\nRUN make all \\\n    && make pack4docker \\\n    && tar -zxf open-falcon-v*.tar.gz -C ${FALCON_DIR} \\\n    && rm -rf ${PROJ_PATH}\n\n# Final container;\nFROM alpine:3.7\nLABEL maintainer laiwei.ustc@gmail.com\nUSER root\n\nENV FALCON_DIR=/open-falcon\n\nRUN mkdir -p $FALCON_DIR/logs && \\\n    apk add --no-cache ca-certificates bash git supervisor\n\nADD docker/supervisord.conf /etc/supervisord.conf\n\nCOPY --from=0 ${FALCON_DIR} ${FALCON_DIR}\n\nEXPOSE 8433 8080\nWORKDIR ${FALCON_DIR}\n\nCMD [\"/usr/bin/supervisord\", \"-c\", \"/etc/supervisord.conf\"]\n\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "CMD = agent aggregator graph hbs judge nodata transfer gateway api alarm falcon2p8s\nTARGET = open-falcon\nPACKAGES ?= $(shell go list ./... | grep -v /vendor/)\nGOFILES := $(shell find . -name \"*.go\" -type f -not -path \"./vendor/*\")\nGOFMT ?= gofmt \"-s\"\nVERSION := $(shell cat VERSION)\n\nall: $(CMD) $(TARGET)\n\n.PHONY: misspell-check\nmisspell-check:\n\t@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \\\n\t\tgo get -u github.com/client9/misspell/cmd/misspell; \\\n\tfi\n\tmisspell -error $(GOFILES)\n\n.PHONY: misspell\nmisspell:\n\t@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \\\n\t\tgo get -u github.com/client9/misspell/cmd/misspell; \\\n\tfi\n\tmisspell -w $(GOFILES)\n\nvet:\n\tgo vet $(PACKAGES)\n\nfmt:\n\t$(GOFMT) -w $(GOFILES)\n\n.PHONY: fmt-check\nfmt-check:\n\t# get all go files and run go fmt on them\n\t@diff=$$($(GOFMT) -d $(GOFILES)); \\\n\tif [ -n \"$$diff\" ]; then \\\n\t\techo \"Please run 'make fmt' and commit the result:\"; \\\n\t\techo \"$${diff}\"; \\\n\t\texit 1; \\\n\tfi;\n\n$(CMD):\n\tif [ $@ = \"gateway\" ]; then \\\n\t\tGO111MODULE=on go build -ldflags \"-X main.BinaryName=gateway -X main.GitCommit=`git rev-parse --short HEAD` -X main.Version=$(VERSION)\" \\\n\t\t\t-o bin/gateway/falcon-gateway ./modules/transfer ; \\\n\telse \\\n\t\tGO111MODULE=on go build -ldflags \"-X main.BinaryName=$@ -X main.GitCommit=`git rev-parse --short HEAD` -X main.Version=$(VERSION)\" \\\n\t\t\t-o bin/$@/falcon-$@ ./modules/$@ ; \\\n\tfi\n\n.PHONY: $(TARGET)\n$(TARGET): $(GOFILES)\n\tGO111MODULE=on go build -ldflags \"-X main.BinaryName=Open-Falcon -X main.GitCommit=`git rev-parse --short HEAD` -X main.Version=$(VERSION)\" -o open-falcon\n\ncheckbin: bin/ config/ open-falcon\n\npack: checkbin\n\t@if [ -e out ] ; then rm -rf out; fi\n\t@mkdir out\n\t@$(foreach var,$(CMD),mkdir -p ./out/$(var)/bin;)\n\t@$(foreach var,$(CMD),mkdir -p ./out/$(var)/config;)\n\t@$(foreach var,$(CMD),mkdir -p ./out/$(var)/logs;)\n\t@$(foreach var,$(CMD),cp ./config/$(var).json ./out/$(var)/config/cfg.json;)\n\t@$(foreach var,$(CMD),cp ./bin/$(var)/falcon-$(var) ./out/$(var)/bin;)\n\t@cp -r ./modules/agent/public ./out/agent/\n\t@(cd ./out && ln -s ./agent/public ./public)\n\t@(cd ./out && mkdir -p ./agent/plugin && ln -s ./agent/plugin ./plugin)\n\t@cp -r ./modules/api/data ./out/api/\n\t@mkdir out/graph/data\n\t@bash ./config/confgen.sh\n\t@cp $(TARGET) ./out/$(TARGET)\n\ttar -C out -zcf open-falcon-v$(VERSION).tar.gz .\n\t@rm -rf out\n\npack4docker: checkbin\n\t@if [ -e out ] ; then rm -rf out; fi\n\t@mkdir out\n\t@$(foreach var,$(CMD),mkdir -p ./out/$(var)/bin;)\n\t@$(foreach var,$(CMD),mkdir -p ./out/$(var)/config;)\n\t@$(foreach var,$(CMD),mkdir -p ./out/$(var)/logs;)\n\t@$(foreach var,$(CMD),cp ./config/$(var).json ./out/$(var)/config/cfg.json;)\n\t@$(foreach var,$(CMD),cp ./bin/$(var)/falcon-$(var) ./out/$(var)/bin;)\n\t@if expr \"$(CMD)\" : \"agent\" > /dev/null; then \\\n\t\t(cp -r ./modules/agent/public ./out/agent/); \\\n\t\t(cd ./out && ln -s ./agent/public ./public); \\\n\t\t(cd ./out && mkdir -p ./agent/plugin && ln -s ./agent/plugin ./plugin); \\\n\tfi\n\t@if expr \"$(CMD)\" : \"api\" > /dev/null; then \\\n\t\tcp -r ./modules/api/data ./out/api/; \\\n\tfi\n\t@if expr \"$(CMD)\" : \"graph\" > /dev/null; then \\\n\t\tmkdir out/graph/data; \\\n\tfi\n\t@cp ./docker/ctrl.sh ./out/ && chmod +x ./out/ctrl.sh\n\t@cp $(TARGET) ./out/$(TARGET)\n\ttar -C out -zcf open-falcon-v$(VERSION).tar.gz .\n\t@rm -rf out\n\n.PHONY: test\ntest:\n\t@go test ./modules/api/test\n\nclean:\n\t@rm -rf ./bin\n\t@rm -rf ./out\n\t@rm -rf ./$(TARGET)\n\t@rm -rf open-falcon-v$(VERSION).tar.gz\n\n.PHONY: clean all agent aggregator graph hbs judge nodata transfer gateway api alarm\n"
  },
  {
    "path": "NOTICE",
    "content": "Open-Falcon\n\nCopyright (c) 2014-2017 Xiaomi, Inc. All Rights Reserved.\n\nThis product is licensed to you under the Apache License, Version 2.0 (the \"License\").\nYou may not use this product except in compliance with the License.\n\nThis product may include a number of subcomponents with separate copyright notices\nand license terms. Your use of these subcomponents is subject to the terms and\nconditions of the subcomponent's license, as noted in the LICENSE file.\n"
  },
  {
    "path": "README.md",
    "content": "# Falcon+\n\n![Open-Falcon](./logo.png)\n\n[![Build Status](https://travis-ci.org/open-falcon/falcon-plus.svg?branch=plus-dev)](https://travis-ci.org/open-falcon/falcon-plus)\n[![License](https://img.shields.io/badge/LICENSE-Apache2.0-ff69b4.svg)](http://www.apache.org/licenses/LICENSE-2.0.html)\n[![Backers on Open Collective](https://opencollective.com/falcon-plus/backers/badge.svg)](#backers)\n[![Sponsors on Open Collective](https://opencollective.com/falcon-plus/sponsors/badge.svg)](#sponsors)\n\n# Notice\n\nIf you are heavily using k8s and adopting microservices architecture, we recommend you to upgrade to use [Nightingale](https://github.com/ccfos/nightingale) building your modern monitoring system.\n\n- [Nightingale](https://github.com/ccfos/nightingale) is an enterprise-level cloud-native monitoring tool, which can be used as drop-in replacement of Prometheus for alerting and management.\n- [Categraf](https://github.com/flashcatcloud/categraf) is one-stop telemetry collector for Nightingale / Prometheus / M3DB / VictoriaMetrics / Thanos / Influxdb / TDengine.\n\nIt is recommended that you use [FlashDuty](https://flashcat.cloud/product/flashduty?from=categraf) as the OnCall system to realize alarm aggregation convergence, claiming, upgrading, scheduling, and coordination, so that the alarm can be reached efficiently and ensure that the alarm processing is not missed.\n\n\n# Documentations\n\n- [Usage](http://book.open-falcon.org)\n- [Open-Falcon API](http://open-falcon.org/falcon-plus)\n\n# Prerequisite\n\n- Git >= 1.7.5\n- Go >= 1.6\n\n# Getting Started\n\n## Docker\n\nPlease refer to ./docker/[README.md](https://github.com/open-falcon/falcon-plus/blob/master/docker/README.md).\n\n## Build from source\n**before start, please make sure you prepared this:**\n\n```\nyum install -y redis\nyum install -y mysql-server\n\n```\n\n*NOTE: be sure to check redis and mysql-server have successfully started.*\n\nAnd then\n\n```\n# Please make sure that you have set `$GOPATH` and `$GOROOT` correctly.\n# If you have not golang in your host, please follow [https://golang.org/doc/install] to install golang.\n\nmkdir -p $GOPATH/src/github.com/open-falcon\ncd $GOPATH/src/github.com/open-falcon\ngit clone https://github.com/open-falcon/falcon-plus.git\n\n```\n\n**And do not forget to init the database first (if you have not loaded the database schema before)**\n\n```\ncd $GOPATH/src/github.com/open-falcon/falcon-plus/scripts/mysql/db_schema/\nmysql -h 127.0.0.1 -u root -p < 1_uic-db-schema.sql\nmysql -h 127.0.0.1 -u root -p < 2_portal-db-schema.sql\nmysql -h 127.0.0.1 -u root -p < 3_dashboard-db-schema.sql\nmysql -h 127.0.0.1 -u root -p < 4_graph-db-schema.sql\nmysql -h 127.0.0.1 -u root -p < 5_alarms-db-schema.sql\n```\n\n**NOTE: if you are upgrading from v0.1 to v0.2.0(or above),then**. [More upgrading instruction](http://www.jianshu.com/p/6fb2c2b4d030)\n\n    mysql -h 127.0.0.1 -u root -p < 5_alarms-db-schema.sql\n\n# Compilation\n\n```\ncd $GOPATH/src/github.com/open-falcon/falcon-plus/\n\n# make all modules\nmake all\n\n# make specified module\nmake agent\n\n# pack all modules\nmake pack\n```\n\n* *after `make pack` you will got `open-falcon-vx.x.x.tar.gz`*\n* *if you want to edit configure file for each module, you can edit `config/xxx.json` before you do `make pack`*\n\n#  Unpack and Decompose\n\n```\nexport WorkDir=\"$HOME/open-falcon\"\nmkdir -p $WorkDir\ntar -xzvf open-falcon-vx.x.x.tar.gz -C $WorkDir\ncd $WorkDir\n```\n\n# Start all modules in single host\n```\ncd $WorkDir\n./open-falcon start\n\n# check modules status\n./open-falcon check\n\n```\n\n# Run More Open-Falcon Commands\n\nfor example:\n\n```\n# ./open-falcon [start|stop|restart|check|monitor|reload] module\n./open-falcon start agent\n\n./open-falcon check\n        falcon-graph         UP           53007\n          falcon-hbs         UP           53014\n        falcon-judge         UP           53020\n     falcon-transfer         UP           53026\n       falcon-nodata         UP           53032\n   falcon-aggregator         UP           53038\n        falcon-agent         UP           53044\n      falcon-gateway         UP           53050\n          falcon-api         UP           53056\n        falcon-alarm         UP           53063\n```\n\n* For debugging , You can check `$WorkDir/$moduleName/logs/xxx.log`\n\n# Install Frontend Dashboard\n- Follow [this](https://github.com/open-falcon/dashboard).\n\n**NOTE: if you want to use grafana as the dashboard, please check [this](https://github.com/open-falcon/grafana-openfalcon-datasource).**\n\n# Package Release\n\n```\nmake clean all pack\n```\n\n# API Standard\n- [API Standard](https://github.com/open-falcon/falcon-plus/blob/master/api-standard.md)\n\n\n# Q&A\n\n- Any issue or question is welcome, Please feel free to open [github issues](https://github.com/open-falcon/falcon-plus/issues) :)\n- [FAQ](http://book.open-falcon.org/zh_0_2/faq/)\n\n\n## Contributors\n\nThis project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].\n<a href=\"https://github.com/open-falcon/falcon-plus/contributors\"><img src=\"https://opencollective.com/falcon-plus/contributors.svg?width=890&button=false\" /></a>\n"
  },
  {
    "path": "VERSION",
    "content": "0.3.x\n"
  },
  {
    "path": "api-standard.md",
    "content": "# HTTP API建议规范\n\n## 说明\n本规范参考阮一峰的《[RESTful API设计指南](http://www.ruanyifeng.com/blog/2014/05/restful_api.html)》编写，部分内容做了适应性的调整和修改。\n\n## 协议\n本文档目前只针对HTTP与HTTPS协议，提供参考规范和建议。\n\n## 域名\n应尽量将API模块部署在专用域名之下。\n```\nhttp://api.open-falcon.com\n```\n\n## 版本(Versioning)\n应将API版本号放入URL。\n```\nhttp://api.open-falcon.com/v1/\n```\n\n## 路径(Endpoint)\n路径又称``“终点”(endpoint)``，表示API的具体网址。\n\n 路径中以``“/”``区分的每一项都应该是``小写英文单词``，若包含多个单词，需要用``下划线``分隔。\n在RESTful架构中，每个网址代表一种``资源（resource）``，所以网址中不应包含动词，如show、delete等。只能有名词，而且所用的名词往往与数据库的表格名对应。\n\n一般来说，数据库中的表都是同种记录的``“集合”（collection）``，所以API中的名词也应该使用``复数``。\n\n以Open-Falcon举例，API模块提供各种关于监控系统的信息，包括数据及报警：\n```\n· http://api.open-falcon.com/v1/counters\n· http://api.open-falcon.com/v1/strategies\n· http://api.open-falcon.com/v1/points\n```\n\n## HTTP动词\n对于资源的具体操作类型，由HTTP动词表示。\n\n常用的HTTP动词有下面五个（括号里是对应的SQL命令）。\n\n```\n· GET（SELECT）：从服务器取出资源（一项或多项）\n· POST（CREATE）：在服务器新建一个资源\n· PUT（UPDATE）：在服务器更新资源（客户端提供改变后的完整资源）\n· PATCH（UPDATE）：在服务器更新资源（客户端提供改变的属性）\n· DELETE（DELETE）：从服务器删除资源\n```\nPATCH一般不常用，更新资源建议使用```PUT```。\n\n还有两个不常用的动词。\n```\nHEAD：获取资源的元数据。\nOPTIONS：获取信息，关于资源的哪些属性是客户端可以改变的。\n```\n\n以下是一些例子\n```\n· GET /v1/users : 获取所有的用户\n· GET /v1/users/{int:ID} : 获取指定的用户信息\n· POST /v1/users : 新增一个用户\n· PUT /v1/users/{int:ID} : 更新某个指定用户的信息(提供用户的全部信息)\n· PATCH /v1/users/{int:ID}  : 更新某个指定用户的信息（提供用户的部分信息）\n```\n\n## 请求参数、请求体\n如果记录数很多，服务器不可能都将他们返回给用户。API应该提供参数，支持过滤结果返回。\n下面是一些常见的参数。\n```\n· ?limit=10 : 指定返回记录的数量\n· ?offset=10 : 指定返回记录的开始位置\n· ?page=2&per_page=100 : 指定第几页，以及每页的记录数\n· ?sortby=name&order=asc : 指定返回结果按照哪个属性排序，以及排序顺序\n· ?type_id=1 : 指定筛选条件\n```\n其中，参数的命名规则为``snake_case``，即单词全部小写，单词间使用下划线分隔。 \n\n参数的设计允许存在``冗余``，即允许API路径和URL参数偶尔有重复。比如，GET /services/ID/domains 与 GET /services?domain_id=ID 的含义是相同的。\n\n另外，参考HTTP协议(1.0版和1.1版)的主要设计者Roy Thomas Fielding所言，任何HTTP请求都允许包含请求体，但发送一个请求体非空的GET请求是没有意义的。因此GET请求请求体应该为``空``。\n\n对于POST、PUT、DELETE请求，若请求体不为空，则请求体格式应该为JSON，如: \n```\n{\n\t\"id\" : 1,\n\t\"name\" : \"ZhangSan\"\n}\n```\n需要注意的是，JSON中key的命名规则同样需要遵循``snake_case``。 \n\n## 状态码（Status Code）\n服务器向用户返回的状态码和提示信息，常见的有以下一些（方括号中是该状态码对应的HTTP动词）。\n```\n· 200 OK - [GET]：服务器成功返回用户请求的数据，该操作是幂等的（Idempotent）。\n· 201 CREATED - [POST/PUT/PATCH]：用户新建或修改数据成功。\n· 202 Accepted - [*]：表示一个请求已经进入后台排队（异步任务）\n· 204 NO CONTENT - [DELETE]：用户删除数据成功。\n· 400 INVALID REQUEST - [POST/PUT/PATCH]：用户发出的请求有错误，服务器没有进行新建或修改数据的操作，该操作是幂等的。\n· 401 Unauthorized - [*]：表示用户没有权限（令牌、用户名、密码错误）。\n· 403 Forbidden - [*] 表示用户得到授权（与401错误相对），但是访问是被禁止的。\n· 404 NOT FOUND - [*]：用户发出的请求针对的是不存在的记录，服务器没有进行操作，该操作是幂等的。\n· 406 Not Acceptable - [GET]：用户请求的格式不可得（比如用户请求JSON格式，但是只有XML格式）。\n· 410 Gone -[GET]：用户请求的资源被永久删除，且不会再得到的。\n· 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时，发生一个验证错误。\n· 500 INTERNAL SERVER ERROR - [*]：服务器发生错误，用户将无法判断发出的请求是否成功。\n```\n状态码的完整列表，参见[这里](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)。\n\n## 返回结果\n服务器返回的数据格式，统一为``JSON``。针对资源的不同操作，服务器向用户返回的结果\n\n应该符合以下规范：\n```\n· GET /collection : 返回资源对象的列表(数组)\n· DELETE /collection/resource : 返回如下的json响应，其中data为被删除对象.\n· GET /collection/resource : 返回单个资源对象\n· POST /collection : 返回新生成的资源对象\n· PUT /collection/resource : 返回更改后的完整的资源对象 \n```\n\n响应格式统一如下： ``此处草版略复杂，待讨论修正``\n```\n{\n    \"code\": 200,    // http status code\n    \"data\": data,    // return data if success\n    \"ret_msg\": \"return message if failed\",    // return message if failed, when success, it's empty\n    \"debug_msg\": \"used for debug\",    // used for debug when failed,when success, it's emptuy\n    \"url_manual\": \"manual url to show if failed\",    // manual url to show if failed\n    \"url_redirect\": \"used for 3xx results\",    // used for 3xx results\n    “response_type\": \"application/json\"    // response body type\n}\n\n```\n"
  },
  {
    "path": "cmd/check.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/open-falcon/falcon-plus/g\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar Check = &cobra.Command{\n\tUse:   \"check [Module ...]\",\n\tShort: \"Check the status of Open-Falcon modules\",\n\tLong: `\nCheck if the specified Open-Falcon modules are running.\nModules:\n  ` + \"all \" + strings.Join(g.AllModulesInOrder, \" \"),\n\tRunE: check,\n}\n\nfunc check(c *cobra.Command, args []string) error {\n\targs = g.RmDup(args)\n\n\tif len(args) == 0 {\n\t\targs = g.AllModulesInOrder\n\t}\n\n\tfor _, moduleName := range args {\n\t\tif !g.HasModule(moduleName) {\n\t\t\treturn fmt.Errorf(\"%s doesn't exist\", moduleName)\n\t\t}\n\n\t\tif g.IsRunning(moduleName) {\n\t\t\tfmt.Printf(\"%20s %10s %15s \\n\", g.ModuleApps[moduleName], \"UP\", g.Pid(moduleName))\n\t\t} else {\n\t\t\tfmt.Printf(\"%20s %10s %15s \\n\", g.ModuleApps[moduleName], \"DOWN\", \"-\")\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/monitor.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/open-falcon/falcon-plus/g\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar Monitor = &cobra.Command{\n\tUse:   \"monitor [Module ...]\",\n\tShort: \"Display an Open-Falcon module's log\",\n\tLong: `\nDisplay the log of the specified Open-Falcon module.\nA module represents a single node in a cluster.\nModules:\n  ` + strings.Join(g.AllModulesInOrder, \" \"),\n\tRunE: monitor,\n}\n\nfunc checkMonReq(name string) error {\n\tif !g.HasModule(name) {\n\t\treturn fmt.Errorf(\"%s doesn't exist\", name)\n\t}\n\n\tif !g.HasLogfile(name) {\n\t\tr := g.Rel(g.LogPath(name))\n\t\treturn fmt.Errorf(\"expect logfile: %s\", r)\n\t}\n\n\treturn nil\n}\n\nfunc monitor(c *cobra.Command, args []string) error {\n\tif len(args) < 1 {\n\t\treturn c.Usage()\n\t}\n\tvar tailArgs []string = []string{\"-f\"}\n\tfor _, moduleName := range args {\n\t\tif err := checkMonReq(moduleName); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttailArgs = append(tailArgs, g.LogPath(moduleName))\n\t}\n\tcmd := exec.Command(\"tail\", tailArgs...)\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\treturn cmd.Run()\n}\n"
  },
  {
    "path": "cmd/reload.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cmd\n\nimport \"github.com/spf13/cobra\"\n\nvar Reload = &cobra.Command{\n\tUse:   \"reload [Module ...]\",\n\tShort: \"Reload an Open-Falcon module's configuration file\",\n\tLong: `\nReload the configuration file of the specified Open-Falcon module.\nA module represents a single node in a cluster.\nModules:\n  `,\n\tRunE: reload,\n}\n\nfunc reload(c *cobra.Command, args []string) error {\n\tif len(args) != 1 {\n\t\treturn c.Usage()\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/restart.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cmd\n\nimport (\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/g\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar Restart = &cobra.Command{\n\tUse:   \"restart [Module ...]\",\n\tShort: \"Restart Open-Falcon modules\",\n\tLong: `\nRestart the specified Open-Falcon modules and run until a stop command is received.\nA module represents a single node in a cluster.\nModules:\n  ` + \"all \" + strings.Join(g.AllModulesInOrder, \" \"),\n\tRunE: restart,\n}\n\nfunc restart(c *cobra.Command, args []string) error {\n\targs = g.RmDup(args)\n\n\tif len(args) == 0 {\n\t\targs = g.AllModulesInOrder\n\t}\n\n\tfor _, moduleName := range args {\n\t\tif err := stop(c, []string{moduleName}); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif strings.Contains(moduleName, \"graph\") {\n\t\t\ttime.Sleep(2 * time.Second)\n\t\t} else {\n\t\t\ttime.Sleep(1 * time.Second)\n\t\t}\n\t\tif err := start(c, []string{moduleName}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/start.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/g\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar Start = &cobra.Command{\n\tUse:   \"start [Module ...]\",\n\tShort: \"Start Open-Falcon modules\",\n\tLong: `\nStart the specified Open-Falcon modules and run until a stop command is received.\nA module represents a single node in a cluster.\nModules:\n\t` + \"all \" + strings.Join(g.AllModulesInOrder, \" \"),\n\tRunE:          start,\n\tSilenceUsage:  true,\n\tSilenceErrors: true,\n}\n\nvar PreqOrderFlag bool\nvar ConsoleOutputFlag bool\n\nfunc cmdArgs(name string) []string {\n\treturn []string{\"-c\", g.Cfg(name)}\n}\n\nfunc openLogFile(name string) (*os.File, error) {\n\tlogDir := g.LogDir(name)\n\tif err := os.MkdirAll(logDir, 0755); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlogPath := g.LogPath(name)\n\tlogOutput, err := os.OpenFile(logPath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn logOutput, nil\n}\n\nfunc execModule(co bool, name string) error {\n\tcmd := exec.Command(g.Bin(name), cmdArgs(name)...)\n\n\tif co {\n\t\tcmd.Stdout = os.Stdout\n\t\tcmd.Stderr = os.Stderr\n\t\treturn cmd.Run()\n\t}\n\n\tlogOutput, err := openLogFile(name)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer logOutput.Close()\n\tcmd.Stdout = logOutput\n\tcmd.Stderr = logOutput\n\treturn cmd.Start()\n}\n\nfunc checkStartReq(name string) error {\n\tif !g.HasModule(name) {\n\t\treturn fmt.Errorf(\"%s doesn't exist\", name)\n\t}\n\n\tif !g.HasCfg(name) {\n\t\tr := g.Rel(g.Cfg(name))\n\t\treturn fmt.Errorf(\"expect config file: %s\", r)\n\t}\n\n\treturn nil\n}\n\nfunc isStarted(name string) bool {\n\tticker := time.NewTicker(time.Millisecond * 100)\n\tdefer ticker.Stop()\n\ttimeout := time.After(time.Second)\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\tif g.IsRunning(name) {\n\t\t\t\treturn true\n\t\t\t}\n\t\tcase <-timeout:\n\t\t\treturn false\n\t\t}\n\t}\n}\n\nfunc start(c *cobra.Command, args []string) error {\n\targs = g.RmDup(args)\n\n\tif PreqOrderFlag {\n\t\targs = g.PreqOrder(args)\n\t}\n\n\tif len(args) == 0 {\n\t\targs = g.AllModulesInOrder\n\t}\n\n\tfor _, moduleName := range args {\n\t\tif err := checkStartReq(moduleName); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Skip starting if the module is already running\n\t\tif g.IsRunning(moduleName) {\n\t\t\tfmt.Print(\"[\", g.ModuleApps[moduleName], \"] \", g.Pid(moduleName), \"\\n\")\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := execModule(ConsoleOutputFlag, moduleName); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif isStarted(moduleName) {\n\t\t\tfmt.Print(\"[\", g.ModuleApps[moduleName], \"] \", g.Pid(moduleName), \"\\n\")\n\t\t\tcontinue\n\t\t}\n\n\t\treturn fmt.Errorf(\"[%s] failed to start\", g.ModuleApps[moduleName])\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/stop.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/open-falcon/falcon-plus/g\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar Stop = &cobra.Command{\n\tUse:   \"stop [Module ...]\",\n\tShort: \"Stop Open-Falcon modules\",\n\tLong: `\nStop the specified Open-Falcon modules.\nA module represents a single node in a cluster.\nModules:\n  ` + \"all \" + strings.Join(g.AllModulesInOrder, \" \"),\n\tRunE: stop,\n}\n\nfunc stop(c *cobra.Command, args []string) error {\n\targs = g.RmDup(args)\n\n\tif len(args) == 0 {\n\t\targs = g.AllModulesInOrder\n\t}\n\n\tfor _, moduleName := range args {\n\t\tif !g.HasModule(moduleName) {\n\t\t\treturn fmt.Errorf(\"%s doesn't exist\", moduleName)\n\t\t}\n\n\t\tif !g.IsRunning(moduleName) {\n\t\t\tfmt.Print(\"[\", g.ModuleApps[moduleName], \"] down\\n\")\n\t\t\tcontinue\n\t\t}\n\n\t\tcmd := exec.Command(\"kill\", \"-TERM\", g.Pid(moduleName))\n\t\tcmd.Stdout = os.Stdout\n\t\tcmd.Stderr = os.Stderr\n\t\terr := cmd.Run()\n\t\tif err == nil {\n\t\t\tfmt.Print(\"[\", g.ModuleApps[moduleName], \"] down\\n\")\n\t\t\tcontinue\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "common/.gitignore",
    "content": "*.swp\n*.swo\n/var\n.DS_Store\n*.iml\n*.idea\n\n"
  },
  {
    "path": "common/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "common/NOTICE",
    "content": "Open-Falcon\n\nCopyright (c) 2014-2015 Xiaomi, Inc. All Rights Reserved.\n\nThis product is licensed to you under the Apache License, Version 2.0 (the \"License\").\nYou may not use this product except in compliance with the License.\n\nThis product may include a number of subcomponents with separate copyright notices\nand license terms. Your use of these subcomponents is subject to the terms and\nconditions of the subcomponent's license, as noted in the LICENSE file.\n"
  },
  {
    "path": "common/backend_pool/rpc_backends.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage backend_pool\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/rpc\"\n\t\"net/rpc/jsonrpc\"\n\t\"sync\"\n\t\"time\"\n\n\tconnp \"github.com/toolkits/conn_pool\"\n\trpcpool \"github.com/toolkits/conn_pool/rpc_conn_pool\"\n)\n\n// ConnPools Manager\ntype SafeRpcConnPools struct {\n\tsync.RWMutex\n\tM           map[string]*connp.ConnPool\n\tMaxConns    int\n\tMaxIdle     int\n\tConnTimeout int\n\tCallTimeout int\n}\n\nfunc CreateSafeRpcConnPools(maxConns, maxIdle, connTimeout, callTimeout int, cluster []string) *SafeRpcConnPools {\n\tcp := &SafeRpcConnPools{M: make(map[string]*connp.ConnPool), MaxConns: maxConns, MaxIdle: maxIdle,\n\t\tConnTimeout: connTimeout, CallTimeout: callTimeout}\n\n\tct := time.Duration(cp.ConnTimeout) * time.Millisecond\n\tfor _, address := range cluster {\n\t\tif _, exist := cp.M[address]; exist {\n\t\t\tcontinue\n\t\t}\n\t\tcp.M[address] = createOneRpcPool(address, address, ct, maxConns, maxIdle)\n\t}\n\n\treturn cp\n}\n\nfunc CreateSafeJsonrpcConnPools(maxConns, maxIdle, connTimeout, callTimeout int, cluster []string) *SafeRpcConnPools {\n\tcp := &SafeRpcConnPools{M: make(map[string]*connp.ConnPool), MaxConns: maxConns, MaxIdle: maxIdle,\n\t\tConnTimeout: connTimeout, CallTimeout: callTimeout}\n\n\tct := time.Duration(cp.ConnTimeout) * time.Millisecond\n\tfor _, address := range cluster {\n\t\tif _, exist := cp.M[address]; exist {\n\t\t\tcontinue\n\t\t}\n\t\tcp.M[address] = createOneJsonrpcPool(address, address, ct, maxConns, maxIdle)\n\t}\n\n\treturn cp\n}\n\n// 同步发送, 完成发送或超时后 才能返回\nfunc (this *SafeRpcConnPools) Call(addr, method string, args interface{}, resp interface{}) error {\n\tconnPool, exists := this.Get(addr)\n\tif !exists {\n\t\treturn fmt.Errorf(\"%s has no connection pool\", addr)\n\t}\n\n\tconn, err := connPool.Fetch()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%s get connection fail: conn %v, err %v. proc: %s\", addr, conn, err, connPool.Proc())\n\t}\n\n\trpcClient := conn.(*rpcpool.RpcClient)\n\tcallTimeout := time.Duration(this.CallTimeout) * time.Millisecond\n\n\tdone := make(chan error, 1)\n\tgo func() {\n\t\tdone <- rpcClient.Call(method, args, resp)\n\t}()\n\n\tselect {\n\tcase <-time.After(callTimeout):\n\t\tconnPool.ForceClose(conn)\n\t\treturn fmt.Errorf(\"%s, call timeout\", addr)\n\tcase err = <-done:\n\t\tif err != nil {\n\t\t\tconnPool.ForceClose(conn)\n\t\t\terr = fmt.Errorf(\"%s, call failed, err %v. proc: %s\", addr, err, connPool.Proc())\n\t\t} else {\n\t\t\tconnPool.Release(conn)\n\t\t}\n\t\treturn err\n\t}\n}\n\nfunc (this *SafeRpcConnPools) Get(address string) (*connp.ConnPool, bool) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tp, exists := this.M[address]\n\treturn p, exists\n}\n\nfunc (this *SafeRpcConnPools) Destroy() {\n\tthis.Lock()\n\tdefer this.Unlock()\n\taddresses := make([]string, 0, len(this.M))\n\tfor address := range this.M {\n\t\taddresses = append(addresses, address)\n\t}\n\n\tfor _, address := range addresses {\n\t\tthis.M[address].Destroy()\n\t\tdelete(this.M, address)\n\t}\n}\n\nfunc (this *SafeRpcConnPools) Proc() []string {\n\tprocs := []string{}\n\tfor _, cp := range this.M {\n\t\tprocs = append(procs, cp.Proc())\n\t}\n\treturn procs\n}\n\nfunc createOneRpcPool(name string, address string, connTimeout time.Duration, maxConns int, maxIdle int) *connp.ConnPool {\n\tp := connp.NewConnPool(name, address, int32(maxConns), int32(maxIdle))\n\tp.New = func(connName string) (connp.NConn, error) {\n\t\t_, err := net.ResolveTCPAddr(\"tcp\", p.Address)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tconn, err := net.DialTimeout(\"tcp\", p.Address, connTimeout)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn rpcpool.NewRpcClient(rpc.NewClient(conn), connName), nil\n\t}\n\n\treturn p\n}\n\nfunc createOneJsonrpcPool(name string, address string, connTimeout time.Duration, maxConns int, maxIdle int) *connp.ConnPool {\n\tp := connp.NewConnPool(name, address, int32(maxConns), int32(maxIdle))\n\tp.New = func(connName string) (connp.NConn, error) {\n\t\t_, err := net.ResolveTCPAddr(\"tcp\", p.Address)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tconn, err := net.DialTimeout(\"tcp\", p.Address, connTimeout)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn rpcpool.NewRpcClientWithCodec(jsonrpc.NewClientCodec(conn), connName), nil\n\t}\n\n\treturn p\n}\n"
  },
  {
    "path": "common/backend_pool/tsdb_backends.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage backend_pool\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\tconnp \"github.com/toolkits/conn_pool\"\n)\n\n// TSDB\ntype TsdbClient struct {\n\tcli  *struct{ net.Conn }\n\tname string\n}\n\nfunc (t TsdbClient) Name() string {\n\treturn t.name\n}\n\nfunc (t TsdbClient) Closed() bool {\n\treturn t.cli.Conn == nil\n}\n\nfunc (t TsdbClient) Close() error {\n\tif t.cli != nil {\n\t\terr := t.cli.Close()\n\t\tt.cli.Conn = nil\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc newTsdbConnPool(address string, maxConns int, maxIdle int, connTimeout int) *connp.ConnPool {\n\tpool := connp.NewConnPool(\"tsdb\", address, int32(maxConns), int32(maxIdle))\n\n\tpool.New = func(name string) (connp.NConn, error) {\n\t\t_, err := net.ResolveTCPAddr(\"tcp\", address)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tconn, err := net.DialTimeout(\"tcp\", address, time.Duration(connTimeout)*time.Millisecond)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn TsdbClient{\n\t\t\tcli:  &struct{ net.Conn }{conn},\n\t\t\tname: name,\n\t\t}, nil\n\t}\n\n\treturn pool\n}\n\ntype TsdbConnPoolHelper struct {\n\tp           *connp.ConnPool\n\tmaxConns    int\n\tmaxIdle     int\n\tconnTimeout int\n\tcallTimeout int\n\taddress     string\n}\n\nfunc NewTsdbConnPoolHelper(address string, maxConns, maxIdle, connTimeout, callTimeout int) *TsdbConnPoolHelper {\n\treturn &TsdbConnPoolHelper{\n\t\tp:           newTsdbConnPool(address, maxConns, maxIdle, connTimeout),\n\t\tmaxConns:    maxConns,\n\t\tmaxIdle:     maxIdle,\n\t\tconnTimeout: connTimeout,\n\t\tcallTimeout: callTimeout,\n\t\taddress:     address,\n\t}\n}\n\nfunc (t *TsdbConnPoolHelper) Send(data []byte) (err error) {\n\tconn, err := t.p.Fetch()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get connection fail: err %v. proc: %s\", err, t.p.Proc())\n\t}\n\n\tcli := conn.(TsdbClient).cli\n\n\tdone := make(chan error, 1)\n\tgo func() {\n\t\t_, err = cli.Write(data)\n\t\tdone <- err\n\t}()\n\n\tselect {\n\tcase <-time.After(time.Duration(t.callTimeout) * time.Millisecond):\n\t\tt.p.ForceClose(conn)\n\t\treturn fmt.Errorf(\"%s, call timeout\", t.address)\n\tcase err = <-done:\n\t\tif err != nil {\n\t\t\tt.p.ForceClose(conn)\n\t\t\terr = fmt.Errorf(\"%s, call failed, err %v. proc: %s\", t.address, err, t.p.Proc())\n\t\t} else {\n\t\t\tt.p.Release(conn)\n\t\t}\n\t\treturn err\n\t}\n}\n\nfunc (t *TsdbConnPoolHelper) Destroy() {\n\tif t.p != nil {\n\t\tt.p.Destroy()\n\t}\n}\n"
  },
  {
    "path": "common/db/db.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\n// graph.endpoint\ntype GraphEndpoint struct {\n\tId       int64\n\tEndpoint string\n}\n\n// graph.tag_endpoint\ntype GraphTagEndpoint struct {\n\tId         int64\n\tTag        string\n\tEndpointId int64\n}\n\n// graph.endpoint_counter\ntype GraphEndpointCounter struct {\n\tId         int64\n\tEndpointId int64\n\tCounter    string\n}\n"
  },
  {
    "path": "common/model/agent.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n)\n\ntype AgentReportRequest struct {\n\tHostname      string\n\tIP            string\n\tAgentVersion  string\n\tPluginVersion string\n}\n\nfunc (this *AgentReportRequest) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Hostname:%s, IP:%s, AgentVersion:%s, PluginVersion:%s>\",\n\t\tthis.Hostname,\n\t\tthis.IP,\n\t\tthis.AgentVersion,\n\t\tthis.PluginVersion,\n\t)\n}\n\ntype AgentUpdateInfo struct {\n\tLastUpdate    int64\n\tReportRequest *AgentReportRequest\n}\n\ntype AgentHeartbeatRequest struct {\n\tHostname string\n\tChecksum string\n}\n\nfunc (this *AgentHeartbeatRequest) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Hostname: %s, Checksum: %s>\",\n\t\tthis.Hostname,\n\t\tthis.Checksum,\n\t)\n}\n\ntype AgentPluginsResponse struct {\n\tPlugins   []string\n\tTimestamp int64\n}\n\nfunc (this *AgentPluginsResponse) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Plugins:%v, Timestamp:%v>\",\n\t\tthis.Plugins,\n\t\tthis.Timestamp,\n\t)\n}\n\n// e.g. net.port.listen or proc.num\ntype BuiltinMetric struct {\n\tMetric string\n\tTags   string\n}\n\nfunc (this *BuiltinMetric) String() string {\n\treturn fmt.Sprintf(\n\t\t\"%s/%s\",\n\t\tthis.Metric,\n\t\tthis.Tags,\n\t)\n}\n\ntype BuiltinMetricResponse struct {\n\tMetrics   []*BuiltinMetric\n\tChecksum  string\n\tTimestamp int64\n}\n\nfunc (this *BuiltinMetricResponse) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Metrics:%v, Checksum:%s, Timestamp:%v>\",\n\t\tthis.Metrics,\n\t\tthis.Checksum,\n\t\tthis.Timestamp,\n\t)\n}\n\ntype BuiltinMetricSlice []*BuiltinMetric\n\nfunc (this BuiltinMetricSlice) Len() int {\n\treturn len(this)\n}\nfunc (this BuiltinMetricSlice) Swap(i, j int) {\n\tthis[i], this[j] = this[j], this[i]\n}\nfunc (this BuiltinMetricSlice) Less(i, j int) bool {\n\treturn this[i].String() < this[j].String()\n}\n"
  },
  {
    "path": "common/model/event.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n)\n\n// 机器监控和实例监控都会产生Event，共用这么一个struct\ntype Event struct {\n\tId          string            `json:\"id\"`\n\tStrategy    *Strategy         `json:\"strategy\"`\n\tExpression  *Expression       `json:\"expression\"`\n\tStatus      string            `json:\"status\"` // OK or PROBLEM\n\tEndpoint    string            `json:\"endpoint\"`\n\tLeftValue   float64           `json:\"leftValue\"`\n\tCurrentStep int               `json:\"currentStep\"`\n\tEventTime   int64             `json:\"eventTime\"`\n\tPushedTags  map[string]string `json:\"pushedTags\"`\n}\n\nfunc (this *Event) FormattedTime() string {\n\treturn utils.UnixTsFormat(this.EventTime)\n}\n\nfunc (this *Event) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Endpoint:%s, Status:%s, Strategy:%v, Expression:%v, LeftValue:%s, CurrentStep:%d, PushedTags:%v, TS:%s>\",\n\t\tthis.Endpoint,\n\t\tthis.Status,\n\t\tthis.Strategy,\n\t\tthis.Expression,\n\t\tutils.ReadableFloat(this.LeftValue),\n\t\tthis.CurrentStep,\n\t\tthis.PushedTags,\n\t\tthis.FormattedTime(),\n\t)\n}\n\nfunc (this *Event) ExpressionId() int {\n\tif this.Expression != nil {\n\t\treturn this.Expression.Id\n\t}\n\n\treturn 0\n}\n\nfunc (this *Event) StrategyId() int {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.Id\n\t}\n\n\treturn 0\n}\n\nfunc (this *Event) TplId() int {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.Tpl.Id\n\t}\n\n\treturn 0\n}\n\nfunc (this *Event) Tpl() *Template {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.Tpl\n\t}\n\n\treturn nil\n}\n\nfunc (this *Event) ActionId() int {\n\tif this.Expression != nil {\n\t\treturn this.Expression.ActionId\n\t}\n\n\treturn this.Strategy.Tpl.ActionId\n}\n\nfunc (this *Event) Priority() int {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.Priority\n\t}\n\treturn this.Expression.Priority\n}\n\nfunc (this *Event) Note() string {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.Note\n\t}\n\treturn this.Expression.Note\n}\n\nfunc (this *Event) Metric() string {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.Metric\n\t}\n\treturn this.Expression.Metric\n}\n\nfunc (this *Event) RightValue() float64 {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.RightValue\n\t}\n\treturn this.Expression.RightValue\n}\n\nfunc (this *Event) Operator() string {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.Operator\n\t}\n\treturn this.Expression.Operator\n}\n\nfunc (this *Event) Func() string {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.Func\n\t}\n\treturn this.Expression.Func\n}\n\nfunc (this *Event) MaxStep() int {\n\tif this.Strategy != nil {\n\t\treturn this.Strategy.MaxStep\n\t}\n\treturn this.Expression.MaxStep\n}\n\nfunc (this *Event) Counter() string {\n\treturn fmt.Sprintf(\"%s/%s %s\", this.Endpoint, this.Metric(), utils.SortedTags(this.PushedTags))\n}\n"
  },
  {
    "path": "common/model/expression.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n)\n\ntype Expression struct {\n\tId         int               `json:\"id\"`\n\tMetric     string            `json:\"metric\"`\n\tTags       map[string]string `json:\"tags\"`\n\tFunc       string            `json:\"func\"`       // e.g. max(#3) all(#3)\n\tOperator   string            `json:\"operator\"`   // e.g. < !=\n\tRightValue float64           `json:\"rightValue\"` // critical value\n\tMaxStep    int               `json:\"maxStep\"`\n\tPriority   int               `json:\"priority\"`\n\tNote       string            `json:\"note\"`\n\tActionId   int               `json:\"actionId\"`\n}\n\nfunc (this *Expression) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Id:%d, Metric:%s, Tags:%v, %s%s%s MaxStep:%d, P%d %s ActionId:%d>\",\n\t\tthis.Id,\n\t\tthis.Metric,\n\t\tthis.Tags,\n\t\tthis.Func,\n\t\tthis.Operator,\n\t\tutils.ReadableFloat(this.RightValue),\n\t\tthis.MaxStep,\n\t\tthis.Priority,\n\t\tthis.Note,\n\t\tthis.ActionId,\n\t)\n}\n\ntype ExpressionResponse struct {\n\tExpressions []*Expression `json:\"expressions\"`\n}\n"
  },
  {
    "path": "common/model/graph.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\n\tMUtils \"github.com/open-falcon/falcon-plus/common/utils\"\n)\n\n// DsType 即RRD中的Datasource的类型：GAUGE|COUNTER|DERIVE\ntype GraphItem struct {\n\tEndpoint  string            `json:\"endpoint\"`\n\tMetric    string            `json:\"metric\"`\n\tTags      map[string]string `json:\"tags\"`\n\tValue     float64           `json:\"value\"`\n\tTimestamp int64             `json:\"timestamp\"`\n\tDsType    string            `json:\"dstype\"`\n\tStep      int               `json:\"step\"`\n\tHeartbeat int               `json:\"heartbeat\"`\n\tMin       string            `json:\"min\"`\n\tMax       string            `json:\"max\"`\n}\n\nfunc (this *GraphItem) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Endpoint:%s, Metric:%s, Tags:%v, Value:%v, TS:%d %v DsType:%s, Step:%d, Heartbeat:%d, Min:%s, Max:%s>\",\n\t\tthis.Endpoint,\n\t\tthis.Metric,\n\t\tthis.Tags,\n\t\tthis.Value,\n\t\tthis.Timestamp,\n\t\tMUtils.UnixTsFormat(this.Timestamp),\n\t\tthis.DsType,\n\t\tthis.Step,\n\t\tthis.Heartbeat,\n\t\tthis.Min,\n\t\tthis.Max,\n\t)\n}\n\nfunc (this *GraphItem) PrimaryKey() string {\n\treturn MUtils.PK(this.Endpoint, this.Metric, this.Tags)\n}\n\nfunc (t *GraphItem) Checksum() string {\n\treturn MUtils.Checksum(t.Endpoint, t.Metric, t.Tags)\n}\n\nfunc (this *GraphItem) UUID() string {\n\treturn MUtils.UUID(this.Endpoint, this.Metric, this.Tags, this.DsType, this.Step)\n}\n\ntype GraphDeleteParam struct {\n\tEndpoint string `json:\"endpoint\"`\n\tMetric   string `json:\"metric\"`\n\tStep     int    `json:\"step\"`\n\tDsType   string `json:\"dstype\"`\n\tTags     string `json:\"tags\"`\n}\n\ntype GraphDeleteResp struct {\n}\n\n// ConsolFun 是RRD中的概念，比如：MIN|MAX|AVERAGE\ntype GraphQueryParam struct {\n\tStart     int64  `json:\"start\"`\n\tEnd       int64  `json:\"end\"`\n\tConsolFun string `json:\"consolFuc\"`\n\tEndpoint  string `json:\"endpoint\"`\n\tCounter   string `json:\"counter\"`\n\tStep      int    `json:\"step\"`\n}\n\ntype GraphQueryResponse struct {\n\tEndpoint string     `json:\"endpoint\"`\n\tCounter  string     `json:\"counter\"`\n\tDsType   string     `json:\"dstype\"`\n\tStep     int        `json:\"step\"`\n\tValues   []*RRDData `json:\"Values\"` //大写为了兼容已经再用这个api的用户\n}\n\n// 页面上已经可以看到DsType和Step了，直接带进查询条件，Graph更易处理\ntype GraphAccurateQueryParam struct {\n\tChecksum  string `json:\"checksum\"`\n\tStart     int64  `json:\"start\"`\n\tEnd       int64  `json:\"end\"`\n\tConsolFun string `json:\"consolFuc\"`\n\tDsType    string `json:\"dsType\"`\n\tStep      int    `json:\"step\"`\n}\n\ntype GraphAccurateQueryResponse struct {\n\tValues []*RRDData `json:\"Values\"`\n}\n\ntype JsonFloat float64\n\nfunc (v JsonFloat) MarshalJSON() ([]byte, error) {\n\tf := float64(v)\n\tif math.IsNaN(f) || math.IsInf(f, 0) {\n\t\treturn []byte(\"null\"), nil\n\t} else {\n\t\treturn []byte(fmt.Sprintf(\"%f\", f)), nil\n\t}\n}\n\ntype RRDData struct {\n\tTimestamp int64     `json:\"timestamp\"`\n\tValue     JsonFloat `json:\"value\"`\n}\n\nfunc NewRRDData(ts int64, val float64) *RRDData {\n\treturn &RRDData{Timestamp: ts, Value: JsonFloat(val)}\n}\n\nfunc (this *RRDData) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<RRDData:Value:%v TS:%d %v>\",\n\t\tthis.Value,\n\t\tthis.Timestamp,\n\t\tMUtils.UnixTsFormat(this.Timestamp),\n\t)\n}\n\ntype GraphInfoParam struct {\n\tEndpoint string `json:\"endpoint\"`\n\tCounter  string `json:\"counter\"`\n}\n\ntype GraphInfoResp struct {\n\tConsolFun string `json:\"consolFun\"`\n\tStep      int    `json:\"step\"`\n\tFilename  string `json:\"filename\"`\n}\n\ntype GraphFullyInfo struct {\n\tEndpoint  string `json:\"endpoint\"`\n\tCounter   string `json:\"counter\"`\n\tConsolFun string `json:\"consolFun\"`\n\tStep      int    `json:\"step\"`\n\tFilename  string `json:\"filename\"`\n\tAddr      string `json:\"addr\"`\n}\n\ntype GraphLastParam struct {\n\tEndpoint string `json:\"endpoint\"`\n\tCounter  string `json:\"counter\"`\n}\n\ntype GraphLastResp struct {\n\tEndpoint string   `json:\"endpoint\"`\n\tCounter  string   `json:\"counter\"`\n\tValue    *RRDData `json:\"value\"`\n}\n"
  },
  {
    "path": "common/model/host.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n)\n\ntype Host struct {\n\tId   int\n\tName string\n}\n\nfunc (this *Host) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<id:%d,name:%s>\",\n\t\tthis.Id,\n\t\tthis.Name,\n\t)\n}\n"
  },
  {
    "path": "common/model/influxdb.go",
    "content": "package model\n\ntype InfluxdbItem struct {\n\tMeasurement string                 `json:\"metric\"`\n\tTags        map[string]string      `json:\"tags\"`\n\tFileds      map[string]interface{} `json:\"fileds\"`\n\tTimestamp   int64                  `json:\"timestamp\"`\n}\n"
  },
  {
    "path": "common/model/judge.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n)\n\ntype JudgeItem struct {\n\tEndpoint  string            `json:\"endpoint\"`\n\tMetric    string            `json:\"metric\"`\n\tValue     float64           `json:\"value\"`\n\tTimestamp int64             `json:\"timestamp\"`\n\tJudgeType string            `json:\"judgeType\"`\n\tTags      map[string]string `json:\"tags\"`\n}\n\nfunc (this *JudgeItem) String() string {\n\treturn fmt.Sprintf(\"<Endpoint:%s, Metric:%s, Value:%f, Timestamp:%d, JudgeType:%s Tags:%v>\",\n\t\tthis.Endpoint,\n\t\tthis.Metric,\n\t\tthis.Value,\n\t\tthis.Timestamp,\n\t\tthis.JudgeType,\n\t\tthis.Tags)\n}\n\nfunc (this *JudgeItem) PrimaryKey() string {\n\treturn utils.Md5(utils.PK(this.Endpoint, this.Metric, this.Tags))\n}\n\ntype HistoryData struct {\n\tTimestamp int64   `json:\"timestamp\"`\n\tValue     float64 `json:\"value\"`\n}\n"
  },
  {
    "path": "common/model/metric.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n\n\tMUtils \"github.com/open-falcon/falcon-plus/common/utils\"\n)\n\ntype MetricValue struct {\n\tEndpoint  string      `json:\"endpoint\"`\n\tMetric    string      `json:\"metric\"`\n\tValue     interface{} `json:\"value\"`\n\tStep      int64       `json:\"step\"`\n\tType      string      `json:\"counterType\"`\n\tTags      string      `json:\"tags\"`\n\tTimestamp int64       `json:\"timestamp\"`\n}\n\nfunc (this *MetricValue) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Endpoint:%s, Metric:%s, Type:%s, Tags:%s, Step:%d, Time:%d, Value:%v>\",\n\t\tthis.Endpoint,\n\t\tthis.Metric,\n\t\tthis.Type,\n\t\tthis.Tags,\n\t\tthis.Step,\n\t\tthis.Timestamp,\n\t\tthis.Value,\n\t)\n}\n\n// Same As `MetricValue`\ntype JsonMetaData struct {\n\tMetric      string      `json:\"metric\"`\n\tEndpoint    string      `json:\"endpoint\"`\n\tTimestamp   int64       `json:\"timestamp\"`\n\tStep        int64       `json:\"step\"`\n\tValue       interface{} `json:\"value\"`\n\tCounterType string      `json:\"counterType\"`\n\tTags        string      `json:\"tags\"`\n}\n\nfunc (t *JsonMetaData) String() string {\n\treturn fmt.Sprintf(\"<JsonMetaData Endpoint:%s, Metric:%s, Tags:%s, DsType:%s, Step:%d, Value:%v, Timestamp:%d>\",\n\t\tt.Endpoint, t.Metric, t.Tags, t.CounterType, t.Step, t.Value, t.Timestamp)\n}\n\ntype MetaData struct {\n\tMetric      string            `json:\"metric\"`\n\tEndpoint    string            `json:\"endpoint\"`\n\tTimestamp   int64             `json:\"timestamp\"`\n\tStep        int64             `json:\"step\"`\n\tValue       float64           `json:\"value\"`\n\tCounterType string            `json:\"counterType\"`\n\tTags        map[string]string `json:\"tags\"`\n}\n\nfunc (t *MetaData) String() string {\n\treturn fmt.Sprintf(\"<MetaData Endpoint:%s, Metric:%s, Timestamp:%d, Step:%d, Value:%f, Tags:%v>\",\n\t\tt.Endpoint, t.Metric, t.Timestamp, t.Step, t.Value, t.Tags)\n}\n\nfunc (t *MetaData) PK() string {\n\treturn MUtils.PK(t.Endpoint, t.Metric, t.Tags)\n}\n"
  },
  {
    "path": "common/model/nodata.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n\tttime \"github.com/toolkits/time\"\n)\n\ntype NodataItem struct {\n\tCounter string `json:\"counter\"`\n\tTs      int64  `json:\"ts\"`\n\tFStatus string `json:\"fstatus\"`\n\tFTs     int64  `json:\"fts\"`\n}\n\nfunc (this *NodataItem) String() string {\n\treturn fmt.Sprintf(\"{NodataItem counter:%s ts:%s fecthStatus:%s fetchTs:%s}\",\n\t\tthis.Counter, ttime.FormatTs(this.Ts), this.FStatus, ttime.FormatTs(this.FTs))\n}\n\ntype NodataConfig struct {\n\tId       int               `json:\"id\"`\n\tName     string            `json:\"name\"`\n\tObjType  string            `json:\"objType\"`\n\tEndpoint string            `json:\"endpoint\"`\n\tMetric   string            `json:\"metric\"`\n\tTags     map[string]string `json:\"tags\"`\n\tType     string            `json:\"type\"`\n\tStep     int64             `json:\"step\"`\n\tMock     float64           `json:\"mock\"`\n}\n\nfunc NewNodataConfig(id int, name string, objType string, endpoint string, metric string, tags map[string]string, dstype string, step int64, mock float64) *NodataConfig {\n\treturn &NodataConfig{id, name, objType, endpoint, metric, tags, dstype, step, mock}\n}\n\nfunc (this *NodataConfig) String() string {\n\treturn fmt.Sprintf(\"{NodataConfig id:%d, name:%s, objType:%s, endpoint:%s, metric:%s, tags:%s, type:%s, step:%d, mock:%f}\",\n\t\tthis.Id, this.Name, this.ObjType, this.Endpoint, this.Metric, utils.SortedTags(this.Tags), this.Type, this.Step, this.Mock)\n}\n"
  },
  {
    "path": "common/model/prometheus.go",
    "content": "package model\n\n// MetricType Prometheus指标类型：GAUGE|COUNTER\ntype P8sItem struct {\n\tEndpoint   string            `json:\"endpoint\"`\n\tMetric     string            `json:\"metric\"`\n\tTags       map[string]string `json:\"tags\"`\n\tValue      float64           `json:\"value\"`\n\tTimestamp  int64             `json:\"timestamp\"`\n\tMetricType string            `json:\"metric_type\"`\n\tStep       int               `json:\"step\"`\n}\n"
  },
  {
    "path": "common/model/rpc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n)\n\n// code == 0 => success\n// code == 1 => bad request\ntype SimpleRpcResponse struct {\n\tCode int `json:\"code\"`\n}\n\nfunc (this *SimpleRpcResponse) String() string {\n\treturn fmt.Sprintf(\"<Code: %d>\", this.Code)\n}\n\ntype NullRpcRequest struct {\n}\n"
  },
  {
    "path": "common/model/strategy.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n)\n\ntype Strategy struct {\n\tId         int               `json:\"id\"`\n\tMetric     string            `json:\"metric\"`\n\tTags       map[string]string `json:\"tags\"`\n\tFunc       string            `json:\"func\"`       // e.g. max(#3) all(#3)\n\tOperator   string            `json:\"operator\"`   // e.g. < !=\n\tRightValue float64           `json:\"rightValue\"` // critical value\n\tMaxStep    int               `json:\"maxStep\"`\n\tPriority   int               `json:\"priority\"`\n\tNote       string            `json:\"note\"`\n\tTpl        *Template         `json:\"tpl\"`\n}\n\nfunc (this *Strategy) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Id:%d, Metric:%s, Tags:%v, %s%s%s MaxStep:%d, P%d, %s, %v>\",\n\t\tthis.Id,\n\t\tthis.Metric,\n\t\tthis.Tags,\n\t\tthis.Func,\n\t\tthis.Operator,\n\t\tutils.ReadableFloat(this.RightValue),\n\t\tthis.MaxStep,\n\t\tthis.Priority,\n\t\tthis.Note,\n\t\tthis.Tpl,\n\t)\n}\n\ntype HostStrategy struct {\n\tHostname   string     `json:\"hostname\"`\n\tStrategies []Strategy `json:\"strategies\"`\n}\n\ntype StrategiesResponse struct {\n\tHostStrategies []*HostStrategy `json:\"hostStrategies\"`\n}\n"
  },
  {
    "path": "common/model/template.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n)\n\ntype Template struct {\n\tId       int    `json:\"id\"`\n\tName     string `json:\"name\"`\n\tParentId int    `json:\"parentId\"`\n\tActionId int    `json:\"actionId\"`\n\tCreator  string `json:\"creator\"`\n}\n\nfunc (this *Template) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Id:%d, Name:%s, ParentId:%d, ActionId:%d, Creator:%s>\",\n\t\tthis.Id,\n\t\tthis.Name,\n\t\tthis.ParentId,\n\t\tthis.ActionId,\n\t\tthis.Creator,\n\t)\n}\n"
  },
  {
    "path": "common/model/transfer.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n)\n\ntype TransferResponse struct {\n\tMessage string\n\tTotal   int\n\tInvalid int\n\tLatency int64\n}\n\nfunc (this *TransferResponse) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Total=%v, Invalid:%v, Latency=%vms, Message:%s>\",\n\t\tthis.Total,\n\t\tthis.Invalid,\n\t\tthis.Latency,\n\t\tthis.Message,\n\t)\n}\n"
  },
  {
    "path": "common/model/tsdb.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype TsdbItem struct {\n\tMetric    string            `json:\"metric\"`\n\tTags      map[string]string `json:\"tags\"`\n\tValue     float64           `json:\"value\"`\n\tTimestamp int64             `json:\"timestamp\"`\n}\n\nfunc (this *TsdbItem) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Metric:%s, Tags:%v, Value:%v, TS:%d>\",\n\t\tthis.Metric,\n\t\tthis.Tags,\n\t\tthis.Value,\n\t\tthis.Timestamp,\n\t)\n}\n\nfunc (this *TsdbItem) TsdbString() (s string) {\n\ts = fmt.Sprintf(\"put %s %d %.3f \", this.Metric, this.Timestamp, this.Value)\n\n\tfor k, v := range this.Tags {\n\t\tkey := strings.ToLower(strings.Replace(k, \" \", \"_\", -1))\n\t\tvalue := strings.Replace(v, \" \", \"_\", -1)\n\t\ts += key + \"=\" + value + \" \"\n\t}\n\n\treturn s\n}\n"
  },
  {
    "path": "common/proc/proc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage proc\n\nimport (\n\t\"sync\"\n\t\"time\"\n)\n\nconst (\n\tDefaultOtherMaxSize      = 100 // 默认的 自定义统计字段的最大值\n\tDefaultSCounterQpsPeriod = 1   // QPS计算周期, 默认值为1s\n)\n\n// 基本的计数器\ntype SCounterBase struct {\n\tsync.RWMutex\n\tName string\n\tCnt  int64\n\tTime string\n\tts   int64\n\t// 自定义统计指标\n\tOther map[string]interface{}\n}\n\nfunc NewSCounterBase(name string) *SCounterBase {\n\tuts := time.Now().Unix()\n\treturn &SCounterBase{Name: name, Cnt: 0, Time: formatTs(uts), ts: uts,\n\t\tOther: make(map[string]interface{})}\n}\n\nfunc (this *SCounterBase) Get() *SCounterBase {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this\n}\n\n// to be abandoned\nfunc (this *SCounterBase) Set(cnt int64) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tthis.Cnt = cnt\n\tthis.ts = time.Now().Unix()\n\tthis.Time = formatTs(this.ts)\n}\n\nfunc (this *SCounterBase) SetCnt(cnt int64) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tthis.Cnt = cnt\n\tthis.ts = time.Now().Unix()\n\tthis.Time = formatTs(this.ts)\n}\n\nfunc (this *SCounterBase) PutOther(key string, value interface{}) bool {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tret := false\n\t_, exist := this.Other[key]\n\tif exist {\n\t\tthis.Other[key] = value\n\t\tret = true\n\t} else {\n\t\tif len(this.Other) < DefaultOtherMaxSize {\n\t\t\tthis.Other[key] = value\n\t\t\tret = true\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc formatTs(ts int64) string {\n\treturn time.Unix(ts, 0).Format(\"2006-01-02 15:04:05\")\n}\n\n// QPS统计,只支持 增加计数操作\ntype SCounterQps struct {\n\tsync.RWMutex\n\tName string\n\tCnt  int64\n\tQps  int64\n\tTime string\n\tts   int64\n\t// for qps\n\tlastTs  int64\n\tlastCnt int64\n\t// 自定义统计指标\n\tOther map[string]interface{}\n}\n\nfunc NewSCounterQps(name string) *SCounterQps {\n\tuts := time.Now().Unix()\n\treturn &SCounterQps{Name: name, Cnt: 0, Time: formatTs(uts), ts: uts,\n\t\tQps: 0, lastCnt: 0, lastTs: uts,\n\t\tOther: make(map[string]interface{})}\n}\n\nfunc (this *SCounterQps) Get() *SCounterQps {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\n\tthis.incrByDirty(0) // update qps\n\treturn this\n}\n\nfunc (this *SCounterQps) Incr() {\n\tthis.IncrBy(int64(1))\n}\n\nfunc (this *SCounterQps) IncrBy(incr int64) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tthis.incrByDirty(incr)\n}\n\nfunc (this *SCounterQps) PutOther(key string, value interface{}) bool {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tret := false\n\t_, exist := this.Other[key]\n\tif exist {\n\t\tthis.Other[key] = value\n\t\tret = true\n\t} else {\n\t\tif len(this.Other) < DefaultOtherMaxSize {\n\t\t\tthis.Other[key] = value\n\t\t\tret = true\n\t\t}\n\t}\n\n\treturn ret\n}\n\n// 操作我的时候,请加写锁\nfunc (this *SCounterQps) incrByDirty(incr int64) {\n\tthis.Cnt += incr\n\tthis.ts = time.Now().Unix()\n\tthis.Time = formatTs(this.ts)\n\n\t// qps\n\tif this.ts-this.lastTs > DefaultSCounterQpsPeriod {\n\t\tthis.Qps = int64((this.Cnt - this.lastCnt) / (this.ts - this.lastTs))\n\t\tthis.lastTs = this.ts\n\t\tthis.lastCnt = this.Cnt\n\t}\n}\n"
  },
  {
    "path": "common/sdk/.gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n*.swp\n*.swo\n*.log\n.idea\n.DS_Store\n/sdk*\n/gitversion"
  },
  {
    "path": "common/sdk/README.md",
    "content": ""
  },
  {
    "path": "common/sdk/requests/auth_request.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage requests\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"github.com/toolkits/net/httplib\"\n\t\"time\"\n)\n\nfunc CurlPlus(uri, method, token_name, token_sig string, headers, params map[string]string) (req *httplib.BeegoHttpRequest, err error) {\n\tif method == \"GET\" {\n\t\treq = httplib.Get(uri)\n\t} else if method == \"POST\" {\n\t\treq = httplib.Post(uri)\n\t} else if method == \"PUT\" {\n\t\treq = httplib.Put(uri)\n\t} else if method == \"DELETE\" {\n\t\treq = httplib.Delete(uri)\n\t} else if method == \"HEAD\" {\n\t\treq = httplib.Head(uri)\n\t} else {\n\t\terr = errors.New(\"invalid http method\")\n\t\treturn\n\t}\n\n\treq = req.SetTimeout(1*time.Second, 5*time.Second)\n\n\ttoken, _ := json.Marshal(map[string]string{\n\t\t\"name\": token_name,\n\t\t\"sig\":  token_sig,\n\t})\n\treq.Header(\"Apitoken\", string(token))\n\n\tfor hk, hv := range headers {\n\t\treq.Header(hk, hv)\n\t}\n\n\tfor pk, pv := range params {\n\t\treq.Param(pk, pv)\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "common/sdk/requests/post.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage requests\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc PostJsonBody(url string, v interface{}) (response []byte, err error) {\n\tbs, err := json.Marshal(v)\n\tif err != nil {\n\t\treturn response, err\n\t}\n\n\tbf := bytes.NewBuffer(bs)\n\n\tresp, err := http.Post(url, \"application/json\", bf)\n\tif err != nil {\n\t\treturn response, err\n\t}\n\n\tdefer resp.Body.Close()\n\treturn ioutil.ReadAll(resp.Body)\n\n}\n"
  },
  {
    "path": "common/sdk/sender/linkedlist.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\t\"container/list\"\n\t\"sync\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n)\n\ntype SafeLinkedList struct {\n\tsync.RWMutex\n\tL *list.List\n}\n\nfunc NewSafeLinkedList() *SafeLinkedList {\n\treturn &SafeLinkedList{L: list.New()}\n}\n\nfunc (this *SafeLinkedList) PopBack(limit int) []*model.JsonMetaData {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tsz := this.L.Len()\n\tif sz == 0 {\n\t\treturn []*model.JsonMetaData{}\n\t}\n\n\tif sz < limit {\n\t\tlimit = sz\n\t}\n\n\tret := make([]*model.JsonMetaData, 0, limit)\n\tfor i := 0; i < limit; i++ {\n\t\te := this.L.Back()\n\t\tret = append(ret, e.Value.(*model.JsonMetaData))\n\t\tthis.L.Remove(e)\n\t}\n\n\treturn ret\n}\n\nfunc (this *SafeLinkedList) PushFront(v interface{}) *list.Element {\n\tthis.Lock()\n\tdefer this.Unlock()\n\treturn this.L.PushFront(v)\n}\n\nfunc (this *SafeLinkedList) Front() *list.Element {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.L.Front()\n}\n\nfunc (this *SafeLinkedList) Len() int {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.L.Len()\n}\n"
  },
  {
    "path": "common/sdk/sender/make.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n)\n\nfunc MakeMetaData(endpoint, metric, tags string, val interface{}, counterType string, step_and_ts ...int64) *model.JsonMetaData {\n\tmd := model.JsonMetaData{\n\t\tEndpoint:    endpoint,\n\t\tMetric:      metric,\n\t\tTags:        tags,\n\t\tValue:       val,\n\t\tCounterType: counterType,\n\t}\n\n\targc := len(step_and_ts)\n\tif argc == 0 {\n\t\tmd.Step = 60\n\t\tmd.Timestamp = time.Now().Unix()\n\t} else if argc == 1 {\n\t\tmd.Step = step_and_ts[0]\n\t\tmd.Timestamp = time.Now().Unix()\n\t} else if argc == 2 {\n\t\tmd.Step = step_and_ts[0]\n\t\tmd.Timestamp = step_and_ts[1]\n\t}\n\n\treturn &md\n}\n\nfunc MakeGaugeValue(endpoint, metric, tags string, val interface{}, step_and_ts ...int64) *model.JsonMetaData {\n\treturn MakeMetaData(endpoint, metric, tags, val, \"GAUGE\", step_and_ts...)\n}\n\nfunc MakeCounterValue(endpoint, metric, tags string, val interface{}, step_and_ts ...int64) *model.JsonMetaData {\n\treturn MakeMetaData(endpoint, metric, tags, val, \"COUNTER\", step_and_ts...)\n}\n\nfunc PushGauge(endpoint, metric, tags string, val interface{}, step_and_ts ...int64) {\n\tmd := MakeGaugeValue(endpoint, metric, tags, val, step_and_ts...)\n\tMetaDataQueue.PushFront(md)\n}\n\nfunc PushCounter(endpoint, metric, tags string, val interface{}, step_and_ts ...int64) {\n\tmd := MakeCounterValue(endpoint, metric, tags, val, step_and_ts...)\n\tMetaDataQueue.PushFront(md)\n}\n\nfunc Push(endpoint, metric, tags string, val interface{}, counterType string, step_and_ts ...int64) {\n\tmd := MakeMetaData(endpoint, metric, tags, val, counterType, step_and_ts...)\n\tMetaDataQueue.PushFront(md)\n}\n"
  },
  {
    "path": "common/sdk/sender/push.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n)\n\nfunc PostPush(L []*model.JsonMetaData) error {\n\tbs, err := json.Marshal(L)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbf := bytes.NewBuffer(bs)\n\n\tresp, err := http.Post(PostPushUrl, \"application/json\", bf)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer resp.Body.Close()\n\tbody, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcontent := string(body)\n\n\tif resp.StatusCode != 200 {\n\t\treturn fmt.Errorf(\"status code %d != 200, response: %s\", resp.StatusCode, content)\n\t}\n\n\tif Debug {\n\t\tlog.Println(\"[D] response:\", content)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "common/sdk/sender/sender.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\t\"log\"\n\t\"time\"\n)\n\nconst LIMIT = 200\n\nvar MetaDataQueue = NewSafeLinkedList()\nvar PostPushUrl string\nvar Debug bool\n\nfunc StartSender() {\n\tgo startSender()\n}\n\nfunc startSender() {\n\tfor {\n\t\tL := MetaDataQueue.PopBack(LIMIT)\n\t\tif len(L) == 0 {\n\t\t\ttime.Sleep(time.Millisecond * 200)\n\t\t\tcontinue\n\t\t}\n\n\t\terr := PostPush(L)\n\t\tif err != nil {\n\t\t\tlog.Println(\"[E] push to transfer fail\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "common/utils/counter.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"fmt\"\n)\n\nfunc Counter(metric string, tags map[string]string) string {\n\tif tags == nil || len(tags) == 0 {\n\t\treturn metric\n\t}\n\treturn fmt.Sprintf(\"%s/%s\", metric, SortedTags(tags))\n}\n"
  },
  {
    "path": "common/utils/date.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"time\"\n)\n\nfunc UnixTsFormat(ts int64) string {\n\treturn time.Unix(ts, 0).Format(\"2006-01-02 15:04:05\")\n}\n"
  },
  {
    "path": "common/utils/formatter.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc ReadableFloat(raw float64) string {\n\tval := strconv.FormatFloat(raw, 'f', 5, 64)\n\tif strings.Contains(val, \".\") {\n\t\tval = strings.TrimRight(val, \"0\")\n\t\tval = strings.TrimRight(val, \".\")\n\t}\n\n\treturn val\n}\n"
  },
  {
    "path": "common/utils/func.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"bytes\"\n\t\"math/rand\"\n\t\"strconv\"\n\t\"time\"\n)\n\nfunc PK(endpoint, metric string, tags map[string]string) string {\n\tret := bufferPool.Get().(*bytes.Buffer)\n\tret.Reset()\n\tdefer bufferPool.Put(ret)\n\n\tif tags == nil || len(tags) == 0 {\n\t\tret.WriteString(endpoint)\n\t\tret.WriteString(\"/\")\n\t\tret.WriteString(metric)\n\n\t\treturn ret.String()\n\t}\n\tret.WriteString(endpoint)\n\tret.WriteString(\"/\")\n\tret.WriteString(metric)\n\tret.WriteString(\"/\")\n\tret.WriteString(SortedTags(tags))\n\treturn ret.String()\n}\n\nfunc PK2(endpoint, counter string) string {\n\tret := bufferPool.Get().(*bytes.Buffer)\n\tret.Reset()\n\tdefer bufferPool.Put(ret)\n\n\tret.WriteString(endpoint)\n\tret.WriteString(\"/\")\n\tret.WriteString(counter)\n\n\treturn ret.String()\n}\n\nfunc UUID(endpoint, metric string, tags map[string]string, dstype string, step int) string {\n\tret := bufferPool.Get().(*bytes.Buffer)\n\tret.Reset()\n\tdefer bufferPool.Put(ret)\n\n\tif tags == nil || len(tags) == 0 {\n\t\tret.WriteString(endpoint)\n\t\tret.WriteString(\"/\")\n\t\tret.WriteString(metric)\n\t\tret.WriteString(\"/\")\n\t\tret.WriteString(dstype)\n\t\tret.WriteString(\"/\")\n\t\tret.WriteString(strconv.Itoa(step))\n\n\t\treturn ret.String()\n\t}\n\tret.WriteString(endpoint)\n\tret.WriteString(\"/\")\n\tret.WriteString(metric)\n\tret.WriteString(\"/\")\n\tret.WriteString(SortedTags(tags))\n\tret.WriteString(\"/\")\n\tret.WriteString(dstype)\n\tret.WriteString(\"/\")\n\tret.WriteString(strconv.Itoa(step))\n\n\treturn ret.String()\n}\n\nfunc Checksum(endpoint string, metric string, tags map[string]string) string {\n\tpk := PK(endpoint, metric, tags)\n\treturn Md5(pk)\n}\n\nfunc ChecksumOfUUID(endpoint, metric string, tags map[string]string, dstype string, step int64) string {\n\treturn Md5(UUID(endpoint, metric, tags, dstype, int(step)))\n}\n\nfunc init() {\n\trand.Seed(time.Now().UTC().UnixNano())\n}\n\nfunc RandString(l int) string {\n\tbytes := make([]byte, l)\n\tfor i := 0; i < l; i++ {\n\t\tbytes[i] = byte(RandInt(65, 90))\n\t}\n\treturn string(bytes)\n}\n\nfunc RandInt(min int, max int) int {\n\treturn min + rand.Intn(max-min)\n}\n"
  },
  {
    "path": "common/utils/func_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc origPK(endpoint, metric string, tags map[string]string) string {\n\tif tags == nil || len(tags) == 0 {\n\t\treturn fmt.Sprintf(\"%s/%s\", endpoint, metric)\n\t}\n\treturn fmt.Sprintf(\"%s/%s/%s\", endpoint, metric, SortedTags(tags))\n}\n\nfunc origPK2(endpoint, counter string) string {\n\treturn fmt.Sprintf(\"%s/%s\", endpoint, counter)\n}\n\nfunc origUUID(endpoint, metric string, tags map[string]string, dstype string, step int) string {\n\tif tags == nil || len(tags) == 0 {\n\t\treturn fmt.Sprintf(\"%s/%s/%s/%d\", endpoint, metric, dstype, step)\n\t}\n\treturn fmt.Sprintf(\"%s/%s/%s/%s/%d\", endpoint, metric, SortedTags(tags), dstype, step)\n}\n\nvar pkCase = []struct {\n\tendpoint string\n\tmetric   string\n\ttags     map[string]string\n\texcept   string\n}{\n\t{\"endpoint1\", \"metric1\", nil, \"endpoint1/metric1\"},\n\t{\"endpoint1\", \"metric1\", map[string]string{}, \"endpoint1/metric1\"},\n\t{\"endpoint1\", \"metric1\", map[string]string{\"k1\": \"v1\", \"k2\": \"v2\"}, \"endpoint1/metric1/k1=v1,k2=v2\"},\n\t{\"endpoint1\", \"metric1\", map[string]string{\"k2\": \"v2\", \"k1\": \"v1\"}, \"endpoint1/metric1/k1=v1,k2=v2\"},\n}\n\nvar pk2Case = []struct {\n\tendpoint string\n\tcounter  string\n\texcept   string\n}{\n\t{\"endpoint1\", \"counter1\", \"endpoint1/counter1\"},\n}\n\nvar uuidCase = []struct {\n\tendpoint string\n\tmetric   string\n\ttags     map[string]string\n\tdstype   string\n\tstep     int\n\texcept   string\n}{\n\t{\"endpoint1\", \"metric1\", nil, \"ds\", 10, \"endpoint1/metric1/ds/10\"},\n\t{\"endpoint1\", \"metric1\", map[string]string{}, \"ds\", 10, \"endpoint1/metric1/ds/10\"},\n\t{\"endpoint1\", \"metric1\", map[string]string{\"k1\": \"v1\", \"k2\": \"v2\"}, \"ds\", 10, \"endpoint1/metric1/k1=v1,k2=v2/ds/10\"},\n\t{\"endpoint1\", \"metric1\", map[string]string{\"k2\": \"v2\", \"k1\": \"v1\"}, \"ds\", 10, \"endpoint1/metric1/k1=v1,k2=v2/ds/10\"},\n}\n\nfunc Test_PK(t *testing.T) {\n\tfor _, pk := range pkCase {\n\t\tif PK(pk.endpoint, pk.metric, pk.tags) != origPK(pk.endpoint, pk.metric, pk.tags) || PK(pk.endpoint, pk.metric, pk.tags) != pk.except {\n\t\t\tt.Error(\"not except\")\n\t\t}\n\t}\n}\n\nfunc Test_PK2(t *testing.T) {\n\tfor _, pk2 := range pk2Case {\n\t\tif PK2(pk2.endpoint, pk2.counter) != origPK2(pk2.endpoint, pk2.counter) || PK2(pk2.endpoint, pk2.counter) != pk2.except {\n\t\t\tt.Error(\"not except\")\n\t\t}\n\t}\n}\n\nfunc Test_UUID(t *testing.T) {\n\tfor _, uuid := range uuidCase {\n\t\tif UUID(uuid.endpoint, uuid.metric, uuid.tags, uuid.dstype, uuid.step) != origUUID(uuid.endpoint, uuid.metric, uuid.tags, uuid.dstype, uuid.step) ||\n\t\t\tUUID(uuid.endpoint, uuid.metric, uuid.tags, uuid.dstype, uuid.step) != uuid.except {\n\t\t\tt.Error(\"not except\")\n\t\t}\n\t}\n}\n\nvar (\n\ttestTags = map[string]string{\"k1\": \"v1\", \"k2\": \"v2\"}\n)\n\nfunc Benchmark_PK(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tPK(\"endpoint1\", \"metric1\", testTags)\n\t}\n}\n\nfunc Benchmark_PK_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigPK(\"endpoint1\", \"metric1\", testTags)\n\t}\n}\n\nfunc Benchmark_PK2(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tPK2(\"endpoint1\", \"counter1\")\n\t}\n}\n\nfunc Benchmark_PK2_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigPK2(\"endpoint1\", \"counter1\")\n\t}\n}\n\nfunc Benchmark_UUID(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tUUID(\"endpoint1\", \"metric1\", testTags, \"dt\", 10)\n\t}\n}\n\nfunc Benchmark_UUID_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigUUID(\"endpoint1\", \"metric1\", testTags, \"dt\", 10)\n\t}\n}\n"
  },
  {
    "path": "common/utils/map.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"sort\"\n)\n\n// TODO 以下的部分, 考虑放到公共组件库\nfunc KeysOfMap(m map[string]string) []string {\n\tkeys := make(sort.StringSlice, len(m))\n\ti := 0\n\tfor key := range m {\n\t\tkeys[i] = key\n\t\ti++\n\t}\n\n\tkeys.Sort()\n\treturn []string(keys)\n}\n"
  },
  {
    "path": "common/utils/md5.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n)\n\nfunc Md5(raw string) string {\n\th := md5.Sum([]byte(raw))\n\treturn hex.EncodeToString(h[:])\n}\n"
  },
  {
    "path": "common/utils/md5_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n)\n\nfunc origMd5(raw string) string {\n\th := md5.New()\n\tio.WriteString(h, raw)\n\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n\nfunc Test_Md5(t *testing.T) {\n\tif Md5(\"1234567890123\") != origMd5(\"1234567890123\") {\n\t\tt.Error(\"not expect\")\n\t}\n}\n\nfunc Benchmark_Md5(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tMd5(\"1234567890123\")\n\t}\n}\n\nfunc Benchmark_Md5_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigMd5(\"1234567890123\")\n\t}\n}\n"
  },
  {
    "path": "common/utils/objpool.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"bytes\"\n\t\"sync\"\n)\n\nvar bufferPool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}\n"
  },
  {
    "path": "common/utils/statistics.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport \"math\"\n\nfunc ComputeMean(values []float64) float64 {\n\tvar sum float64\n\n\tfor _, value := range values {\n\t\tsum = sum + value\n\t}\n\n\treturn (sum / float64(len(values)))\n}\n\nfunc ComputeStdDeviation(values []float64) float64 {\n\tvar (\n\t\tmean         float64\n\t\tvp           []float64\n\t\tstdDiv, temp float64\n\t)\n\n\tvp = make([]float64, len(values))\n\n\t/*Calculate mean of the data points*/\n\tmean = ComputeMean(values)\n\t/*Calculate standard deviation of individual data points*/\n\tfor i, v := range values {\n\t\ttemp = v - mean\n\t\tvp[i] = (temp * temp)\n\t}\n\n\t/* Finally, Compute standard Deviation of data points\n\t * by taking mean of individual std. Deviation.\n\t */\n\tstdDiv = ComputeMean(vp)\n\treturn float64(math.Sqrt(float64(stdDiv)))\n}\n"
  },
  {
    "path": "common/utils/tags.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\nfunc SortedTags(tags map[string]string) string {\n\tif tags == nil {\n\t\treturn \"\"\n\t}\n\n\tsize := len(tags)\n\n\tif size == 0 {\n\t\treturn \"\"\n\t}\n\n\tret := bufferPool.Get().(*bytes.Buffer)\n\tret.Reset()\n\tdefer bufferPool.Put(ret)\n\n\tif size == 1 {\n\t\tfor k, v := range tags {\n\t\t\tret.WriteString(k)\n\t\t\tret.WriteString(\"=\")\n\t\t\tret.WriteString(v)\n\t\t}\n\t\treturn ret.String()\n\t}\n\n\tkeys := make([]string, size)\n\ti := 0\n\tfor k := range tags {\n\t\tkeys[i] = k\n\t\ti++\n\t}\n\n\tsort.Strings(keys)\n\n\tfor j, key := range keys {\n\t\tret.WriteString(key)\n\t\tret.WriteString(\"=\")\n\t\tret.WriteString(tags[key])\n\t\tif j != size-1 {\n\t\t\tret.WriteString(\",\")\n\t\t}\n\t}\n\n\treturn ret.String()\n}\n\nfunc DictedTagstring(s string) map[string]string {\n\tif s == \"\" {\n\t\treturn map[string]string{}\n\t}\n\n\tif strings.ContainsRune(s, ' ') {\n\t\ts = strings.Replace(s, \" \", \"\", -1)\n\t}\n\n\ttag_dict := make(map[string]string)\n\ttags := strings.Split(s, \",\")\n\tfor _, tag := range tags {\n\t\tidx := strings.IndexRune(tag, '=')\n\t\tif idx != -1 {\n\t\t\ttag_dict[tag[:idx]] = tag[idx+1:]\n\t\t}\n\t}\n\treturn tag_dict\n}\n\nfunc SplitTagsString(s string) (err error, tags map[string]string) {\n\terr = nil\n\ttags = make(map[string]string)\n\n\ts = strings.Replace(s, \" \", \"\", -1)\n\tif s == \"\" {\n\t\treturn\n\t}\n\n\ttagSlice := strings.Split(s, \",\")\n\tfor _, tag := range tagSlice {\n\t\ttag_pair := strings.SplitN(tag, \"=\", 2)\n\t\tif len(tag_pair) == 2 {\n\t\t\ttags[tag_pair[0]] = tag_pair[1]\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"bad tag %s\", tag)\n\t\t\treturn\n\t\t}\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "common/utils/tags_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage utils\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n)\n\nvar testCases4map2string = []struct {\n\ttags   map[string]string\n\texpect string\n}{\n\t{map[string]string{\"1\": \"1\"}, \"1=1\"},\n\t{map[string]string{\"1\": \"1\", \"2\": \"2\"}, \"1=1,2=2\"},\n\t{map[string]string{\"1\": \"1\", \"2\": \"2\", \"0\": \"0\"}, \"0=0,1=1,2=2\"},\n}\n\nvar testCases4string2map = []struct {\n\ttags   string\n\texpect map[string]string\n}{\n\t{\"1=1\", map[string]string{\"1\": \"1\"}},\n\t{\"1=1,2=2\", map[string]string{\"1\": \"1\", \"2\": \"2\"}},\n\t{\"0=0,1=1,2=2\", map[string]string{\"1\": \"1\", \"2\": \"2\", \"0\": \"0\"}},\n\t{\"0,1=1,2=2\", map[string]string{\"1\": \"1\", \"2\": \"2\"}},\n\t{\"0=,1=1,2=2\", map[string]string{\"0\": \"\", \"1\": \"1\", \"2\": \"2\"}},\n\t{\"=0,1=1,2=2\", map[string]string{\"\": \"0\", \"1\": \"1\", \"2\": \"2\"}},\n\t{\"0=0, 1=1, 2=2\", map[string]string{\"0\": \"0\", \"1\": \"1\", \"2\": \"2\"}},\n}\n\nfunc origSortedTags(tags map[string]string) string {\n\tif tags == nil {\n\t\treturn \"\"\n\t}\n\n\tsize := len(tags)\n\n\tif size == 0 {\n\t\treturn \"\"\n\t}\n\n\tif size == 1 {\n\t\tfor k, v := range tags {\n\t\t\treturn fmt.Sprintf(\"%s=%s\", k, v)\n\t\t}\n\t}\n\n\tkeys := make([]string, size)\n\ti := 0\n\tfor k := range tags {\n\t\tkeys[i] = k\n\t\ti++\n\t}\n\n\tsort.Strings(keys)\n\n\tret := make([]string, size)\n\tfor j, key := range keys {\n\t\tret[j] = fmt.Sprintf(\"%s=%s\", key, tags[key])\n\t}\n\n\treturn strings.Join(ret, \",\")\n}\n\nfunc origDictedTagstring(s string) map[string]string {\n\tif s == \"\" {\n\t\treturn map[string]string{}\n\t}\n\ts = strings.Replace(s, \" \", \"\", -1)\n\n\ttag_dict := make(map[string]string)\n\ttags := strings.Split(s, \",\")\n\tfor _, tag := range tags {\n\t\ttag_pair := strings.SplitN(tag, \"=\", 2)\n\t\tif len(tag_pair) == 2 {\n\t\t\ttag_dict[tag_pair[0]] = tag_pair[1]\n\t\t}\n\t}\n\treturn tag_dict\n}\n\nfunc Test_SortedTags(t *testing.T) {\n\tfor _, testCase := range testCases4map2string {\n\t\tif r := SortedTags(testCase.tags); r != testCase.expect || SortedTags(testCase.tags) != origSortedTags(testCase.tags) {\n\t\t\tt.Errorf(\"expect %v, got %v\\n\", testCase.expect, r)\n\t\t}\n\t}\n}\nfunc Test_DictedTagstring(t *testing.T) {\n\tfor _, testCase := range testCases4string2map {\n\t\tr := DictedTagstring(testCase.tags)\n\t\torigR := origDictedTagstring(testCase.tags)\n\n\t\tif len(r) != len(testCase.expect) || len(r) != len(origR) {\n\t\t\tt.FailNow()\n\t\t}\n\t\tfor k, v := range r {\n\t\t\tif expectV, exist := testCase.expect[k]; !exist || v != expectV || v != origR[k] {\n\t\t\t\tt.Errorf(\"expect %v, got %v\\n\", testCase.expect, r)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc Benchmark_SortedTags_1pair(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tSortedTags(map[string]string{\"1\": \"1\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_1pair_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigSortedTags(map[string]string{\"1\": \"1\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_2pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_2pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_3pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_3pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_4pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\", \"4\": \"4\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_4pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\", \"4\": \"4\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_5pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\", \"4\": \"4\", \"5\": \"5\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_5pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\", \"4\": \"4\", \"5\": \"5\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_6pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\", \"4\": \"4\", \"5\": \"5\", \"0\": \"0\"})\n\t}\n}\n\nfunc Benchmark_SortedTags_6pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigSortedTags(map[string]string{\"1\": \"1\", \"2\": \"2\", \"3\": \"3\", \"4\": \"4\", \"5\": \"5\", \"0\": \"0\"})\n\t}\n}\n\nfunc Benchmark_DictedTagstring_1pair(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDictedTagstring(\"1=1\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_1pair_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigDictedTagstring(\"1=1\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_2pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDictedTagstring(\"1=1,2=2\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_2pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigDictedTagstring(\"1=1,2=2\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_3pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDictedTagstring(\"1=1,2=2,3=3\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_3pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigDictedTagstring(\"1=1,2=2,3=3\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_4pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDictedTagstring(\"1=1,2=2,3=3,4=4\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_4pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigDictedTagstring(\"1=1,2=2,3=3,4=4\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_5pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDictedTagstring(\"1=1,2=2,3=3,4=4,5=5\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_5pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigDictedTagstring(\"1=1,2=2,3=3,4=4,5=5\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_6pairs(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tDictedTagstring(\"1=1,2=2,3=3,4=4,5=5,6=6\")\n\t}\n}\n\nfunc Benchmark_DictedTagstring_6pairs_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\torigDictedTagstring(\"1=1,2=2,3=3,4=4,5=5,6=6\")\n\t}\n}\n"
  },
  {
    "path": "config/agent.json",
    "content": "{\n    \"debug\": true,\n    \"hostname\": \"%%AGENT_HOSTNAME%%\",\n    \"ip\": \"\",\n    \"plugin\": {\n        \"enabled\": false,\n        \"dir\": \"./plugin\",\n        \"git\": \"https://github.com/open-falcon/plugin.git\",\n        \"logs\": \"./logs\"\n    },\n    \"heartbeat\": {\n        \"enabled\": true,\n        \"addr\": \"%%HBS_RPC%%\",\n        \"interval\": 60,\n        \"timeout\": 1000\n    },\n    \"transfer\": {\n        \"enabled\": true,\n        \"addrs\": [\n            \"%%TRANSFER_RPC%%\"\n        ],\n        \"interval\": 60,\n        \"timeout\": 1000\n    },\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \":1988\",\n        \"backdoor\": false\n    },\n    \"collector\": {\n        \"ifacePrefix\": [\"eth\", \"em\"],\n        \"mountPoint\": []\n    },\n    \"default_tags\": {\n    },\n    \"ignore\": {\n        \"cpu.busy\": true,\n        \"df.bytes.free\": true,\n        \"df.bytes.total\": true,\n        \"df.bytes.used\": true,\n        \"df.bytes.used.percent\": true,\n        \"df.inodes.total\": true,\n        \"df.inodes.free\": true,\n        \"df.inodes.used\": true,\n        \"df.inodes.used.percent\": true,\n        \"mem.memtotal\": true,\n        \"mem.memused\": true,\n        \"mem.memused.percent\": true,\n        \"mem.memfree\": true,\n        \"mem.swaptotal\": true,\n        \"mem.swapused\": true,\n        \"mem.swapfree\": true\n    }\n}\n"
  },
  {
    "path": "config/aggregator.json",
    "content": "{\n    \"debug\": true,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"%%AGGREGATOR_HTTP%%\"\n    },\n    \"database\": {\n        \"addr\": \"%%MYSQL%%/falcon_portal?loc=Local&parseTime=true\",\n        \"idle\": 10,\n        \"ids\": [1, -1],\n        \"interval\": 55\n    },\n    \"api\": {\n        \"connect_timeout\": 500,\n        \"request_timeout\": 2000,\n        \"plus_api\": \"http://127.0.0.1:8080\",\n        \"plus_api_token\": \"%%PLUS_API_DEFAULT_TOKEN%%\",\n        \"push_api\": \"http://127.0.0.1:1988/v1/push\"\n    }\n}\n"
  },
  {
    "path": "config/alarm.json",
    "content": "{\n    \"log_level\": \"debug\",\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:9912\"\n    },\n    \"redis\": {\n        \"addr\": \"%%REDIS%%\",\n        \"maxIdle\": 5,\n        \"highQueues\": [\n            \"event:p0\",\n            \"event:p1\",\n            \"event:p2\"\n        ],\n        \"lowQueues\": [\n            \"event:p3\",\n            \"event:p4\",\n            \"event:p5\",\n            \"event:p6\"\n        ],\n        \"userIMQueue\": \"/queue/user/im\",\n        \"userSmsQueue\": \"/queue/user/sms\",\n        \"userMailQueue\": \"/queue/user/mail\"\n    },\n    \"api\": {\n        \"im\": \"http://127.0.0.1:10086/wechat\",\n        \"sms\": \"http://127.0.0.1:10086/sms\",\n        \"mail\": \"http://127.0.0.1:10086/mail\",\n        \"dashboard\": \"http://127.0.0.1:8081\",\n        \"plus_api\":\"http://127.0.0.1:8080\",\n        \"plus_api_token\": \"%%PLUS_API_DEFAULT_TOKEN%%\"\n    },\n    \"falcon_portal\": {\n        \"addr\": \"%%MYSQL%%/alarms?charset=utf8&loc=Local\",\n        \"idle\": 10,\n        \"max\": 100\n    },\n    \"worker\": {\n        \"im\": 10,\n        \"sms\": 10,\n        \"mail\": 50\n    },\n    \"housekeeper\": {\n        \"event_retention_days\": 7,\n        \"event_delete_batch\": 100\n    }\n}\n"
  },
  {
    "path": "config/api.json",
    "content": "{\n\t\"log_level\": \"debug\",\n\t\"db\": {\n\t\t\"falcon_portal\": \"%%MYSQL%%/falcon_portal?charset=utf8&parseTime=True&loc=Local\",\n\t\t\"graph\": \"%%MYSQL%%/graph?charset=utf8&parseTime=True&loc=Local\",\n\t\t\"uic\": \"%%MYSQL%%/uic?charset=utf8&parseTime=True&loc=Local\",\n\t\t\"dashboard\": \"%%MYSQL%%/dashboard?charset=utf8&parseTime=True&loc=Local\",\n\t\t\"alarms\": \"%%MYSQL%%/alarms?charset=utf8&parseTime=True&loc=Local\",\n\t\t\"db_bug\": true\n\t},\n\t\"graphs\": {\n\t\t\"cluster\": {\n\t\t\t\"graph-00\": \"%%GRAPH_RPC%%\"\n\t\t},\n\t\t\"max_conns\": 100,\n\t\t\"max_idle\": 100,\n\t\t\"conn_timeout\": 1000,\n\t\t\"call_timeout\": 5000,\n\t\t\"numberOfReplicas\": 500\n\t},\n\t\"metric_list_file\": \"./api/data/metric\",\n\t\"web_port\": \"%%PLUS_API_HTTP%%\",\n\t\"access_control\": true,\n\t\"signup_disable\": false,\n\t\"salt\": \"\",\n\t\"skip_auth\": false,\n\t\"default_token\": \"%%PLUS_API_DEFAULT_TOKEN%%\",\n\t\"gen_doc\": false,\n\t\"gen_doc_path\": \"doc/module.html\"\n}\n"
  },
  {
    "path": "config/confgen.sh",
    "content": "#!/bin/bash\n\nconfs=(\n    '%%AGENT_HTTP%%=0.0.0.0:1988'\n    '%%AGGREGATOR_HTTP%%=0.0.0.0:6055'\n    '%%GRAPH_HTTP%%=0.0.0.0:6071'\n    '%%GRAPH_RPC%%=0.0.0.0:6070'\n    '%%HBS_HTTP%%=0.0.0.0:6031'\n    '%%HBS_RPC%%=0.0.0.0:6030'\n    '%%JUDGE_HTTP%%=0.0.0.0:6081'\n    '%%JUDGE_RPC%%=0.0.0.0:6080'\n    '%%NODATA_HTTP%%=0.0.0.0:6090'\n    '%%TRANSFER_HTTP%%=0.0.0.0:6060'\n    '%%TRANSFER_RPC%%=0.0.0.0:8433'\n    '%%REDIS%%=127.0.0.1:6379'\n    '%%MYSQL%%=root:@tcp(127.0.0.1:3306)'\n    '%%PLUS_API_DEFAULT_TOKEN%%=default-token-used-in-server-side'\n    '%%PLUS_API_HTTP%%=0.0.0.0:8080'\n    '%%AGENT_HOSTNAME%%='\n )\n\nconfigurer() {\n    for i in \"${confs[@]}\"\n    do\n        search=\"${i%%=*}\"\n        replace=\"${i##*=}\"\n\n        uname=`uname`\n        if [ \"$uname\" == \"Darwin\" ] ; then\n            # Note the \"\" and -e  after -i, needed in OS X\n            find ./out/*/config/*.json -type f -exec sed -i .tpl -e \"s/${search}/${replace}/g\" {} \\;\n        else\n            find ./out/*/config/*.json -type f -exec sed -i \"s/${search}/${replace}/g\" {} \\;\n        fi\n    done\n}\nconfigurer\n"
  },
  {
    "path": "config/falcon2p8s.json",
    "content": "{\n    \"log_level\": \"debug\",\n    \"concurrent\": 100,\n    \"http\": {\n        \"listen\": \"0.0.0.0:9090\"\n    },\n    \"rpc\": {\n        \"listen\": \"0.0.0.0:8080\"\n    }\n}"
  },
  {
    "path": "config/gateway.json",
    "content": "{\n    \"debug\": true,\n    \"minStep\": 30,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:16060\"\n    },\n    \"rpc\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:18433\"\n    },\n    \"socket\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:14444\",\n        \"timeout\": 3600\n    },\n    \"judge\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"cluster\": {\n            \"judge-00\" : \"%%JUDGE_RPC%%\"\n        }\n    },\n    \"graph\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"cluster\": {\n            \"graph-00\" : \"%%GRAPH_RPC%%\"\n        }\n    },\n    \"tsdb\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"retry\": 3,\n        \"address\": \"127.0.0.1:8088\"\n    },\n    \"transfer\": {\n        \"enabled\": true,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"retry\": 3,\n        \"cluster\": {\n            \"t1\": \"%%TRANSFER_RPC%%\"\n        }\n    },\n    \"influxdb\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"retry\": 3,\n        \"maxConns\": 32,\n        \"username\": \"admin\",\n        \"password\": \"123456\",\n        \"precision\": \"s\",\n        \"db\": \"foo\",\n        \"address\": \"http://127.0.0.1:8086\",\n        \"timeout\": 5000\n    }\n}\n"
  },
  {
    "path": "config/graph.json",
    "content": "{\n    \"debug\": false,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"%%GRAPH_HTTP%%\"\n    },\n    \"rpc\": {\n        \"enabled\": true,\n        \"listen\": \"%%GRAPH_RPC%%\"\n    },\n    \"rrd\": {\n        \"storage\": \"./data/6070\"\n    },\n    \"db\": {\n        \"dsn\": \"%%MYSQL%%/graph?loc=Local&parseTime=true\",\n        \"maxIdle\": 4\n    },\n    \"callTimeout\": 5000,\n    \"ioWorkerNum\": 64,\n    \"migrate\": {\n            \"enabled\": false,\n            \"concurrency\": 2,\n            \"replicas\": 500,\n            \"cluster\": {\n                    \"graph-00\" : \"127.0.0.1:6070\"\n            }\n    }\n}\n"
  },
  {
    "path": "config/hbs.json",
    "content": "{\n    \"debug\": true,\n    \"database\": \"%%MYSQL%%/falcon_portal?loc=Local&parseTime=true\",\n    \"hosts\": \"\",\n    \"maxConns\": 20,\n    \"maxIdle\": 15,\n    \"listen\": \":6030\",\n    \"trustable\": [\"\"],\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"%%HBS_HTTP%%\"\n    }\n}\n"
  },
  {
    "path": "config/judge.json",
    "content": "{\n    \"debug\": true,\n    \"debugHost\": \"nil\",\n    \"remain\": 11,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"%%JUDGE_HTTP%%\"\n    },\n    \"rpc\": {\n        \"enabled\": true,\n        \"listen\": \"%%JUDGE_RPC%%\"\n    },\n    \"hbs\": {\n        \"servers\": [\"%%HBS_RPC%%\"],\n        \"timeout\": 300,\n        \"interval\": 60\n    },\n    \"alarm\": {\n        \"enabled\": true,\n        \"minInterval\": 300,\n        \"queuePattern\": \"event:p%v\",\n        \"redis\": {\n            \"dsn\": \"%%REDIS%%\",\n            \"maxIdle\": 5,\n            \"connTimeout\": 5000,\n            \"readTimeout\": 5000,\n            \"writeTimeout\": 5000\n        }\n    }\n}\n"
  },
  {
    "path": "config/nodata.json",
    "content": "{\n    \"debug\": true,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"%%NODATA_HTTP%%\"\n    },\n    \"plus_api\":{\n        \"connectTimeout\": 500,\n        \"requestTimeout\": 2000,\n        \"addr\": \"http://127.0.0.1:8080\",\n        \"token\": \"default-token-used-in-server-side\"\n    },\n    \"config\": {\n        \"enabled\": true,\n        \"dsn\": \"%%MYSQL%%/falcon_portal?loc=Local&parseTime=true&wait_timeout=604800\",\n        \"maxIdle\": 4\n    },\n    \"collector\":{\n        \"enabled\": true,\n        \"batch\": 200,\n        \"concurrent\": 10\n    },\n    \"sender\":{\n        \"enabled\": true,\n        \"connectTimeout\": 500,\n        \"requestTimeout\": 2000,\n        \"transferAddr\": \"%%TRANSFER_HTTP%%\",\n        \"batch\": 500\n    }\n}\n"
  },
  {
    "path": "config/transfer.json",
    "content": "{\n    \"debug\": true,\n    \"minStep\": 30,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"%%TRANSFER_HTTP%%\"\n    },\n    \"rpc\": {\n        \"enabled\": true,\n        \"listen\": \"%%TRANSFER_RPC%%\"\n    },\n    \"socket\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:4444\",\n        \"timeout\": 3600\n    },\n    \"judge\": {\n        \"enabled\": true,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"cluster\": {\n            \"judge-00\" : \"%%JUDGE_RPC%%\"\n        }\n    },\n    \"graph\": {\n        \"enabled\": true,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"cluster\": {\n            \"graph-00\" : \"%%GRAPH_RPC%%\"\n        }\n    },\n    \"tsdb\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"retry\": 3,\n        \"address\": \"127.0.0.1:8088\"\n    },\n    \"transfer\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"retry\": 3,\n        \"cluster\": {\n            \"t1\": \"127.0.0.1:8433\"\n        }\n    },\n    \"influxdb\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"retry\": 3,\n        \"maxConns\": 32,\n        \"username\": \"admin\",\n        \"password\": \"123456\",\n        \"precision\": \"s\",\n        \"db\": \"foo\",\n        \"address\": \"http://127.0.0.1:8086\",\n        \"timeout\": 5000\n    },\n    \"p8s_relay\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"notSyncMetrics\": [\n            \"gpu.\",\n            \"snmp.\"\n        ],\n        \"cluster\": {\n            \"p8s-relay-00\" : \"192.168.1.1:8080\",\n            \"p8s-relay-01\" : \"192.168.1.2:8080\"\n        }\n    }\n}\n"
  },
  {
    "path": "docker/README.md",
    "content": "## Running open-falcon container\n\n`the latest version in docker hub is v0.3`\n\n##### 1. Start mysql and init the mysql table before the first running\n\n```\n## start mysql in container\ndocker run -itd \\\n    --name falcon-mysql \\\n    -v /home/work/mysql-data:/var/lib/mysql \\\n    -e MYSQL_ROOT_PASSWORD=test123456 \\\n    -p 3306:3306 \\\n    mysql:5.7\n\n## init mysql table before the first running\ncd /tmp && \\\ngit clone --depth=1 https://github.com/open-falcon/falcon-plus.git && \\\ncd /tmp/falcon-plus/ && \\\nfor x in `ls ./scripts/mysql/db_schema/*.sql`; do\n    echo init mysql table $x ...;\n    docker exec -i falcon-mysql mysql -uroot -ptest123456 < $x;\ndone\n\nrm -rf /tmp/falcon-plus/\n```\n\n##### 2. Start redis in container\n\n```\ndocker run --name falcon-redis -p6379:6379 -d redis:4-alpine3.8\n```\n\n##### 3. Start falcon-plus modules in one container\n\n```\n## pull images from hub.docker.com/openfalcon\ndocker pull openfalcon/falcon-plus:v0.3\n\n## run falcon-plus container\ndocker run -itd --name falcon-plus \\\n        --link=falcon-mysql:db.falcon \\\n        --link=falcon-redis:redis.falcon \\\n        -p 8433:8433 \\\n        -p 8080:8080 \\\n        -e MYSQL_PORT=root:test123456@tcp\\(db.falcon:3306\\) \\\n        -e REDIS_PORT=redis.falcon:6379  \\\n        -v /home/work/open-falcon/data:/open-falcon/data \\\n        -v /home/work/open-falcon/logs:/open-falcon/logs \\\n        openfalcon/falcon-plus:v0.3\n\n## start falcon backend modules, such as graph,api,etc.\ndocker exec falcon-plus sh ctrl.sh start \\\n        graph hbs judge transfer nodata aggregator agent gateway api alarm\n\n## or you can just start/stop/restart specific module as: \ndocker exec falcon-plus sh ctrl.sh start/stop/restart xxx\n\n## check status of backend modules\ndocker exec falcon-plus ./open-falcon check\n\n## or you can check logs at /home/work/open-falcon/logs/ in your host\nls -l /home/work/open-falcon/logs/\n    \n```\n\n##### 4. Start falcon-dashboard in container\n\n```\ndocker run -itd --name falcon-dashboard \\\n    -p 8081:8081 \\\n    --link=falcon-mysql:db.falcon \\\n    --link=falcon-plus:api.falcon \\\n    -e API_ADDR=http://api.falcon:8080/api/v1 \\\n    -e PORTAL_DB_HOST=db.falcon \\\n    -e PORTAL_DB_PORT=3306 \\\n    -e PORTAL_DB_USER=root \\\n    -e PORTAL_DB_PASS=test123456 \\\n    -e PORTAL_DB_NAME=falcon_portal \\\n    -e ALARM_DB_HOST=db.falcon \\\n    -e ALARM_DB_PORT=3306 \\\n    -e ALARM_DB_USER=root \\\n    -e ALARM_DB_PASS=test123456 \\\n    -e ALARM_DB_NAME=alarms \\\n    -w /open-falcon/dashboard openfalcon/falcon-dashboard:v0.2.1  \\\n    './control startfg'\n```\n\n##### 5. Start falcon-agent in container\n\n```\nsudo docker run -d --restart always --name falcon-agent \\\n    -e NUX_ROOTFS=/rootfs \\\n    -v /:/rootfs:ro \\\n    openfalcon/falcon-plus:v0.3 \\\n    ./agent/bin/falcon-agent -c /open-falcon/agent/config/cfg.json\n```\n\n----\n\n## Building open-falcon images from source code\n\n##### Building falcon-plus\n\n```\ncd /tmp && \\\ngit clone https://github.com/open-falcon/falcon-plus.git && \\\ncd /tmp/falcon-plus/ && \\\ndocker build -t falcon-plus:v0.3 .\n```\n\n##### Building falcon-dashboard\n\n```\ncd /tmp && \\\ngit clone https://github.com/open-falcon/dashboard.git  && \\\ncd /tmp/dashboard/ && \\\ndocker build -t falcon-dashboard:v0.2.1 .\n```\n"
  },
  {
    "path": "docker/confgen4docker.sh",
    "content": "#!/bin/bash\n\nconfs=(\n    '%%AGENT_HTTP%%=0.0.0.0:1988'\n    '%%AGGREGATOR_HTTP%%=0.0.0.0:6055'\n    '%%GRAPH_HTTP%%=0.0.0.0:6071'\n    '%%GRAPH_RPC%%=0.0.0.0:6070'\n    '%%HBS_HTTP%%=0.0.0.0:6031'\n    '%%HBS_RPC%%=0.0.0.0:6030'\n    '%%JUDGE_HTTP%%=0.0.0.0:6081'\n    '%%JUDGE_RPC%%=0.0.0.0:6080'\n    '%%NODATA_HTTP%%=0.0.0.0:6090'\n    '%%TRANSFER_HTTP%%=0.0.0.0:6060'\n    '%%TRANSFER_RPC%%=0.0.0.0:8433'\n    '%%PLUS_API_DEFAULT_TOKEN%%=default-token-used-in-server-side'\n    '%%PLUS_API_HTTP%%=0.0.0.0:8080'\n    '%%AGENT_HOSTNAME%%='\n )\n\nconfigurer() {\n    for i in \"${confs[@]}\"\n    do\n        search=\"${i%%=*}\"\n        replace=\"${i##*=}\"\n\n        uname=`uname`\n        if [ \"$uname\" == \"Darwin\" ] ; then\n            # Note the \"\" and -e  after -i, needed in OS X\n            find ./out/*/config/*.json -type f -exec sed -i .tpl -e \"s/${search}/${replace}/g\" {} \\;\n        else\n            find ./out/*/config/*.json -type f -exec sed -i \"s/${search}/${replace}/g\" {} \\;\n        fi\n    done\n}\nconfigurer\n"
  },
  {
    "path": "docker/ctrl.sh",
    "content": "#!/bin/sh\n\nDOCKER_DIR=/open-falcon\nof_bin=$DOCKER_DIR/open-falcon\nDOCKER_HOST_IP=$(route -n | awk '/UG[ \\t]/{print $2}')\n\n# Search $1 and replace with $2 or $3(defualt)\nreplace() {\n    replacement=$2\n    if [ -z \"$replacement\" ]; then\n      replacement=$3\n    fi\n    find $DOCKER_DIR/*/config/*.json -type f -exec sed -i \"s/$1/$replacement/g\" {} \\;\n}\n\nreplace \"%%MYSQL%%\" \"$MYSQL_PORT\" \"$DOCKER_HOST_IP:3306\"\nreplace \"%%REDIS%%\" \"$REDIS_PORT\" \"$DOCKER_HOST_IP:6379\"\nreplace \"%%AGGREGATOR_HTTP%%\" \"$AGGREGATOR_HTTP\" \"0.0.0.0:6055\"\nreplace \"%%GRAPH_HTTP%%\" \"$GRAPH_HTTP\" \"0.0.0.0:6071\"\nreplace \"%%GRAPH_RPC%%\" \"$GRAPH_RPC\" \"0.0.0.0:6070\"\nreplace \"%%HBS_HTTP%%\" \"$HBS_HTTP\" \"0.0.0.0:6031\"\nreplace \"%%HBS_RPC%%\" \"$HBS_RPC\" \"0.0.0.0:6030\"\nreplace \"%%JUDGE_HTTP%%\" \"$JUDGE_HTTP\" \"0.0.0.0:6081\"\nreplace \"%%JUDGE_RPC%%\" \"$JUDGE_RPC\" \"0.0.0.0:6080\"\nreplace \"%%NODATA_HTTP%%\" \"$NODATA_HTTP\" \"0.0.0.0:6090\"\nreplace \"%%TRANSFER_HTTP%%\" \"$TRANSFER_HTTP\" \"0.0.0.0:6060\"\nreplace \"%%TRANSFER_RPC%%\" \"$TRANSFER_RPC\" \"0.0.0.0:8433\"\nreplace \"%%PLUS_API_HTTP%%\" \"$PLUS_API_HTTP\" \"0.0.0.0:8080\"\nreplace \"%%AGENT_HOSTNAME%%\" \"$AGENT_HOSTNAME\" \"\"\n\n#use absolute path of metric_list_file in docker\nTAB=$'\\t'; sed -i \"s|.*metric_list_file.*|${TAB}\\\"metric_list_file\\\": \\\"$DOCKER_DIR/api/data/metric\\\",|g\" $DOCKER_DIR/api/config/*.json;\n\naction=$1\nmodule_name=$2\ncase $action in\n run)\n        $DOCKER_DIR/\"$module_name\"/bin/falcon-\"$module_name\" -c /open-falcon/\"$module_name\"/config/cfg.json\n        ;;\n *)\n        supervisorctl $*\n        ;;\nesac\n"
  },
  {
    "path": "docker/k8s-cluster/Dockerfile.tpl",
    "content": "FROM alpine:3.7\nLABEL maintainer tabsp@qq.com\nUSER root\n\nENV FALCON_DIR=/open-falcon\n# agent\nRUN apk add --no-cache ca-certificates git curl\n# alarm\nADD https://github.com/golang/go/raw/master/lib/time/zoneinfo.zip /usr/local/go/lib/time/zoneinfo.zip\n\nCOPY build/%%MODULE_NAME%% ${FALCON_DIR}/%%MODULE_NAME%%\nWORKDIR ${FALCON_DIR}\n\nCMD [\"/open-falcon/%%MODULE_NAME%%/bin/falcon-%%MODULE_NAME%%\", \"-c\", \"/open-falcon/%%MODULE_NAME%%/config/cfg.json\"]\n"
  },
  {
    "path": "docker/k8s-cluster/README.md",
    "content": "## 分布式部署 open-falcon 到 k8s 集群\n\n### 构建\n\n克隆源码：\n\n```shell\ngit clone https://github.com/open-falcon/falcon-plus.git && cd falcon-plus \n```\n\n编译源码并构建 Docker 镜像\n\n```shell\n./docker/k8s-cluster/build.sh\n```\n\n### 部署\n\n注意点：\n\n1. graph 为有状态组件，部署方式为每个节点一个 Deployment，同时 replica 设置为 1\n2. 所有配置文件使用挂载目录的方式持久化，可以改为 ConfigMap 管理配置\n3. 镜像可以使用构建脚本自己构建后推送到自己的私仓使用（推荐），或者直接使用我构建好的，仓库地址在 docker/k8s-cluster/build.sh 查看或修改"
  },
  {
    "path": "docker/k8s-cluster/build.sh",
    "content": "#!/bin/bash\nMODULES=(\n    'agent'\n    'aggregator'\n    'alarm'\n    'api'\n    'gateway'\n    'graph'\n    'hbs'\n    'judge'\n    'nodata'\n    'transfer'\n)\nDOCKER_REGISTRY=registry.cn-hangzhou.aliyuncs.com/open-falcon\nVERSION=v0.3\n\nclean() {\n    echo \"clean...\"\n    if [ -d \"build\" ]; then\n        rm -rf build/\n    fi\n    mkdir build\n}\n\nbuild() {\n    echo \"build source...\"\n    if [ `uname -m` == \"aarch64\" ]; then\n        BASE_IMAGE=jimmytinsley/makegcc-golang\n    else\n        BASE_IMAGE=openfalcon/makegcc-golang:1.10-alpine\n    fi\n    docker run -it --rm \\\n        --name build \\\n        -v \"$(pwd)\":\"/go/src/github.com/open-falcon/falcon-plus\" \\\n        -w \"/go/src/github.com/open-falcon/falcon-plus\" \\\n        $BASE_IMAGE \\\n        docker/k8s-cluster/init.sh\n}\n\nbuildDockerImages() {\n    echo \"build docker images...\"\n    for i in \"${MODULES[@]}\"; do\n        echo \"build $i\"\n        awk -v module=\"$i\" '{ gsub(/%%MODULE_NAME%%/, module); print $0 }' docker/k8s-cluster/Dockerfile.tpl > docker/k8s-cluster/Dockerfile\n        docker build -f docker/k8s-cluster/Dockerfile -t $DOCKER_REGISTRY/$i:$VERSION .\n        rm docker/k8s-cluster/Dockerfile\n    done\n}\n\nclean\nbuild\nbuildDockerImages\n"
  },
  {
    "path": "docker/k8s-cluster/init.sh",
    "content": "#!/bin/sh\n\napk add --no-cache ca-certificates git bash \\\n&& make all \\\n&& make pack4docker \\\n&& tar -zxf open-falcon-v*.tar.gz -C build \\\n&& rm open-falcon-v*.tar.gz"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-agent.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-agent\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: http\n      port: 1988\n  selector:\n    name: falcon-agent\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-agent\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-agent\n    spec:\n      containers:\n        - name: falcon-agent\n          image: registry.cn-hangzhou.aliyuncs.com/open-falcon/agent:v0.3\n          imagePullPolicy: IfNotPresent\n          ports:\n            - containerPort: 1988\n              name: http\n              protocol: TCP\n          volumeMounts:\n            - mountPath: /open-falcon/agent/config\n              name: falcon-agent-config\n            - mountPath: /etc/localtime\n              name: tz-config\n      volumes:\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-agent/config\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-agent-config\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-aggregator.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-aggregator\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: http\n      port: 6055\n  selector:\n    name: falcon-aggregator\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-aggregator\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-aggregator\n    spec:\n      containers:\n        - name: falcon-aggregator\n          image: registry.cn-hangzhou.aliyuncs.com/open-falcon/aggregator:v0.3\n          imagePullPolicy: IfNotPresent\n          ports:\n            - containerPort: 6055\n              name: http\n              protocol: TCP\n          volumeMounts:\n            - mountPath: /open-falcon/aggregator/config\n              name: falcon-aggregator-config\n            - mountPath: /etc/localtime\n              name: tz-config\n      volumes:\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-aggregator/config\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-aggregator-config\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-alarm.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-alarm\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: http\n      port: 9912\n  selector:\n    name: falcon-alarm\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-alarm\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-alarm\n    spec:\n      containers:\n        - name: falcon-alarm\n          image: registry.cn-hangzhou.aliyuncs.com/open-falcon/alarm:v0.3\n          imagePullPolicy: IfNotPresent\n          ports:\n            - containerPort: 9912\n              name: http\n              protocol: TCP\n          volumeMounts:\n            - mountPath: /open-falcon/alarm/config\n              name: falcon-alarm-config\n            - mountPath: /etc/localtime\n              name: tz-config\n      volumes:\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-alarm/config\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-alarm-config\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-api.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-api\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: http\n      port: 8080\n  selector:\n    name: falcon-api\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-api\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-api\n    spec:\n      containers:\n        - name: falcon-api\n          image: registry.cn-hangzhou.aliyuncs.com/open-falcon/api:v0.3\n          imagePullPolicy: IfNotPresent\n          ports:\n            - containerPort: 8080\n              name: http\n              protocol: TCP\n          volumeMounts:\n            - mountPath: /open-falcon/api/config\n              name: falcon-api-config\n            - mountPath: /etc/localtime\n              name: tz-config\n      volumes:\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-api/config\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-api-config\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-dashboard.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-dashboard\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: http\n      port: 8081\n  selector:\n    name: falcon-dashboard\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-dashboard\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-dashboard\n    spec:\n      containers:\n      - name: falcon-dashboard\n        image: openfalcon/falcon-dashboard:v0.2.1\n        command: [\"sh\",\"-c\",\"cd /open-falcon/dashboard &&  ./control startfg\"]\n        imagePullPolicy: IfNotPresent\n        ports:\n        - containerPort: 8081\n        env:\n        - name: API_ADDR\n          value: http://falcon-api:8080/api/v1\n        - name: PORTAL_DB_HOST\n          value: 127.0.0.1\n        - name: PORTAL_DB_PORT\n          value: \"3306\"\n        - name: PORTAL_DB_USER\n          value: root\n        - name: PORTAL_DB_PASS\n          value: xxx\n        - name: PORTAL_DB_NAME\n          value: falcon_portal\n        - name: ALARM_DB_HOST\n          value: 127.0.0.1\n        - name: ALARM_DB_PORT\n          value: \"3306\"\n        - name: ALARM_DB_USER\n          value: root\n        - name: ALARM_DB_PASS\n          value: root\n        - name: ALARM_DB_NAME\n          value: alarms\n        volumeMounts:\n          - mountPath: /etc/localtime\n            name: tz-config\n      volumes:\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-graph-01.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-graph-01\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: rpc\n      port: 6070\n    - name: http\n      port: 6071\n  selector:\n    name: falcon-graph-01\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-graph-01\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-graph-01\n    spec:\n      containers:\n        - name: falcon-graph-01\n          image: registry.cn-hangzhou.aliyuncs.com/open-falcon/graph:v0.3\n          imagePullPolicy: IfNotPresent\n          ports:\n            - containerPort: 6070\n              name: rpc\n              protocol: TCP\n            - containerPort: 6071\n              name: http\n              protocol: TCP\n          volumeMounts:\n            - mountPath: /open-falcon/graph/config\n              name: falcon-graph-config\n            - mountPath: /open-falcon/graph/data\n              name: falcon-graph-data\n            - mountPath: /etc/localtime\n              name: tz-config\n      volumes:\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-graph/01/config\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-graph-config\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-graph/01/data\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-graph-data\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-hbs.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-hbs\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: rpc\n      port: 6030\n    - name: http\n      port: 6031\n  selector:\n    name: falcon-hbs\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-hbs\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-hbs\n    spec:\n      containers:\n        - name: falcon-hbs\n          image: registry.cn-hangzhou.aliyuncs.com/open-falcon/hbs:v0.3\n          imagePullPolicy: IfNotPresent\n          ports:\n            - containerPort: 6030\n              name: rpc\n              protocol: TCP\n            - containerPort: 6031\n              name: http\n              protocol: TCP\n          volumeMounts:\n            - mountPath: /open-falcon/hbs/config\n              name: falcon-hbs-config\n            - mountPath: /etc/localtime\n              name: tz-config\n      volumes:\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-hbs/config\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-hbs-config\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-judge.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-judge\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: rpc\n      port: 6080\n    - name: http\n      port: 6081\n  selector:\n    name: falcon-judge\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-judge\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-judge\n    spec:\n      containers:\n        - name: falcon-judge\n          image: registry.cn-hangzhou.aliyuncs.com/open-falcon/judge:v0.3\n          imagePullPolicy: IfNotPresent\n          ports:\n            - containerPort: 6080\n              name: rpc\n              protocol: TCP\n            - containerPort: 6081\n              name: http\n              protocol: TCP\n          volumeMounts:\n            - mountPath: /open-falcon/judge/config\n              name: falcon-judge-config\n            - mountPath: /etc/localtime\n              name: tz-config\n      volumes:\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-judge/config\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-judge-config\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-nodata.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-nodata\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: http\n      port: 6090\n  selector:\n    name: falcon-nodata\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-nodata\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-nodata\n    spec:\n      containers:\n        - name: falcon-nodata\n          image: registry.cn-hangzhou.aliyuncs.com/open-falcon/nodata:v0.3\n          imagePullPolicy: IfNotPresent\n          ports:\n            - containerPort: 6090\n              name: http\n              protocol: TCP\n          volumeMounts:\n            - mountPath: /open-falcon/nodata/config\n              name: falcon-nodata-config\n            - mountPath: /etc/localtime\n              name: tz-config\n      volumes:\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-nodata/config\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-nodata-config\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-cluster/modules/falcon-transfer.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  namespace: open-falcon\n  name: falcon-transfer\n  labels:\n    app: open-falcon\nspec:\n  type: ClusterIP\n  ports:\n    - name: http\n      port: 6060\n    - name: rpc\n      port: 8433\n  selector:\n    name: falcon-transfer\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  namespace: open-falcon\n  name: falcon-transfer\n  labels:\n    app: open-falcon\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: falcon-transfer\n    spec:\n      containers:\n        - name: falcon-transfer\n          image: registry.cn-hangzhou.aliyuncs.com/open-falcon/transfer:v0.3\n          imagePullPolicy: IfNotPresent\n          ports:\n            - containerPort: 6060\n              name: http\n              protocol: TCP\n            - containerPort: 8433\n              name: rpc\n              protocol: TCP\n          volumeMounts:\n            - mountPath: /open-falcon/transfer/config\n              name: falcon-transfer-config\n            - mountPath: /etc/localtime\n              name: tz-config\n      volumes:\n        - flexVolume:\n            driver: alicloud/nas\n            options:\n              path: /open-falcon/falcon-transfer/config\n              server: xxx.cn-hangzhou.nas.aliyuncs.com\n              vers: \"4.0\"\n          name: falcon-transfer-config\n        - hostPath:\n            path: /etc/localtime\n            type: ''\n          name: tz-config"
  },
  {
    "path": "docker/k8s-example/README.md",
    "content": "## Running open-falcon in kubernetes\n\nwork on kubernetes 1.14 ,  the `kubectl version` like:\n```\nClient Version: version.Info{Major:\"1\", Minor:\"14\", GitVersion:\"v1.14.0\", GitCommit:\"641856db18352033a0d96dbc99153fa3b27298e5\", GitTreeState:\"clean\", BuildDate:\"2019-03-25T15:53:57Z\", GoVersion:\"go1.12.1\", Compiler:\"gc\", Platform:\"linux/amd64\"}\nServer Version: version.Info{Major:\"1\", Minor:\"14\", GitVersion:\"v1.14.0\", GitCommit:\"641856db18352033a0d96dbc99153fa3b27298e5\", GitTreeState:\"clean\", BuildDate:\"2019-03-25T15:45:25Z\", GoVersion:\"go1.12.1\", Compiler:\"gc\", Platform:\"linux/amd64\"}\n```\n\n##### 1. Start mysql in k8s and init the mysql table before the first running\n\nif mysql is already in k8s you can break this step\n\n```\nkubectl apply -f mysql.yaml\n```\n\ninit mysql table before the first running\n\n```\nsh init_mysql_data.sh\n```\n\n##### 2. Start redis in k8s\n\nif redis is already in k8s you can also break this step\n\n```\nkubectl apply -f redis.yaml\n```\n\n##### 3. Start falcon-plus modules in one pod\n\n```\nkubectl apply -f openfalcon-plus.yaml\n```\n\n##### 4. Start falcon-dashboard in k8s\n\n```\nkubectl apply -f openfalcon-dashboard.yaml\n```\n\n##### 5. browse the dashboard view\n\n```\n[tyhall51@192-168-10-21 k8s-example]$ kubectl get svc\nNAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                         AGE\nkubernetes              ClusterIP   10.96.0.1       <none>        443/TCP                         105d\nmysql                   NodePort    10.110.20.201   <none>        3306:30535/TCP                  25m\nopen-falcon             NodePort    10.97.12.125    <none>        8433:31952/TCP,8080:31957/TCP   53s\nopen-falcon-dashboard   NodePort    10.96.119.231   <none>        8081:30191/TCP                  3s\nredis                   ClusterIP   10.98.212.126   <none>        6379/TCP                        32m\n```\n\nget **open-falcon-dashboard** service localhost port **30191** , then can visit  `http://192.168.10.21:30191` in webrowser 。\n\n\n[mailto](mailto:studyoo@foxmail.com)\n\n"
  },
  {
    "path": "docker/k8s-example/init_mysql_data.sh",
    "content": "#!/bin/sh\n\nmysql_pod=$(kubectl get pods | grep mysql | awk '{print $1}')\ncd /tmp && \\\n\tgit clone --depth=1 https://github.com/open-falcon/falcon-plus && \\\n\tcd /tmp/falcon-plus/ && \\\n\tfor x in `ls ./scripts/mysql/db_schema/*.sql`; do\n\t    echo init mysql table $x ...;\n\t    kubectl exec -it $mysql_pod -- mysql -uroot -p123456 < $x;\n\tdone\n\nrm -rf /tmp/falcon-plus/"
  },
  {
    "path": "docker/k8s-example/mysql.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: mysql\n  labels:\n    app: db\nspec:\n  type: NodePort\n  ports:\n  - port: 3306\n    targetPort: mysqlport\n  selector:\n    app: db\n    name: mysql\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  name: mysql\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        app: db\n        name: mysql\n    spec:\n      containers:\n      - name: mysql\n        image: mysql:5.7\n        imagePullPolicy: IfNotPresent\n        env:\n        - name: TZ\n          value: \"Asia/Shanghai\"\n        - name: MYSQL_ROOT_PASSWORD\n          value: \"123456\"\n        ports:\n        - containerPort: 3306\n          name: mysqlport\n        volumeMounts:\n        - name: mysqldata\n          subPath: mysql_data\n          mountPath: /var/lib/mysql\n      volumes:\n        - name: mysqldata\n          emptyDir: {}\n"
  },
  {
    "path": "docker/k8s-example/openfalcon-dashboard.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: open-falcon-dashboard\n  labels:\n    app: monitor\nspec:\n  type: NodePort\n  ports:\n    - name: web\n      port: 8081\n  selector:\n    name: open-falcon-dashboard\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  name: open-falcon-dashboard\n  labels:\n    app: monitor\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: open-falcon-dashboard\n    spec:\n      containers:\n      - name: open-falcon-dashboard\n        image: openfalcon/falcon-dashboard:v0.2.1\n        command: [\"sh\",\"-c\",\"cd /open-falcon/dashboard &&  ./control startfg\"]\n        imagePullPolicy: IfNotPresent\n        ports:\n        - containerPort: 8081\n        env:\n        - name: API_ADDR\n          value: http://open-falcon:8080/api/v1\n        - name: PORTAL_DB_HOST\n          value: mysql\n        - name: PORTAL_DB_PORT\n          value: \"3306\"\n        - name: PORTAL_DB_USER\n          value: root\n        - name: PORTAL_DB_PASS\n          value: 1qazxsw2\n        - name: PORTAL_DB_NAME\n          value: falcon_portal\n        - name: ALARM_DB_HOST\n          value: mysql\n        - name: ALARM_DB_PORT\n          value: \"3306\"\n        - name: ALARM_DB_USER\n          value: root\n        - name: ALARM_DB_PASS\n          value: 1qazxsw2\n        - name: ALARM_DB_NAME\n          value: alarms\n"
  },
  {
    "path": "docker/k8s-example/openfalcon-plus.yaml",
    "content": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: openfalcon-configmap\ndata:\n  entrypoint.sh: |-\n    #!/bin/bash\n    /bin/sh -c 'sleep 10 && sh ctrl.sh start graph hbs judge transfer nodata aggregator gateway api alarm'  & /usr/bin/supervisord -c /etc/supervisord.conf\n   agent.json: |-\n    {\n        \"debug\": true,\n        \"hostname\": \"\",\n        \"ip\": \"\",\n        \"plugin\": {\n            \"enabled\": false,\n            \"dir\": \"./plugin\",\n            \"git\": \"https://github.com/open-falcon/plugin.git\",\n            \"logs\": \"./logs\"\n        },\n        \"heartbeat\": {\n            \"enabled\": true,\n            \"addr\": \"open-falcon:6030\",\n            \"interval\": 60,\n            \"timeout\": 1000\n        },\n        \"transfer\": {\n            \"enabled\": true,\n            \"addrs\": [\n                \"open-falcon:8433\"\n            ],\n            \"interval\": 60,\n            \"timeout\": 1000\n        },\n        \"http\": {\n            \"enabled\": true,\n            \"listen\": \":1988\",\n            \"backdoor\": false\n        },\n        \"collector\": {\n            \"ifacePrefix\": [\"eth\", \"em\"],\n            \"mountPoint\": []\n        },\n        \"default_tags\": {\n        },\n        \"ignore\": {\n            \"sys.disk.rw\": true,\n            \"df.bytes.free\": true,\n            \"df.bytes.total\": true,\n            \"df.bytes.used\": true,\n            \"df.inodes.total\": true,\n            \"df.inodes.free\": true,\n            \"df.inodes.used\": true,\n            \"mem.memtotal\": true,\n            \"mem.memused\": true,\n            \"mem.memfree\": true,\n            \"mem.swaptotal\": true,\n            \"mem.swapused\": true,\n            \"mem.swapfree\": true,\n            \"df.statistics.total\": true,\n            \"df.statistics.used\": true\n        }\n    }\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: open-falcon\n  labels:\n    app: monitor\nspec:\n  type: NodePort\n  ports:\n    - name: tcp\n      port: 8433\n    - name: web\n      port: 8080\n  selector:\n    name: open-falcon\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  name: open-falcon\n  labels:\n    app: monitor\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        name: open-falcon\n    spec:\n      containers:\n      - name: open-falcon\n        image: openfalcon/falcon-plus:v0.3\n        workingDir: /open-falcon\n        command:\n        - /bin/entrypoint.sh\n        imagePullPolicy: IfNotPresent\n        ports:\n        - containerPort: 8433\n        - containerPort: 8080\n        env:\n        - name: MYSQL_PORT\n          value: root:123456@tcp(mysql:3306)\n        - name: REDIS_PORT\n          value: redis:6379\n        volumeMounts:\n        - name: open-falcon-data\n          mountPath: /open-falcon/data\n        - name: configmap-volume\n          mountPath: /bin/entrypoint.sh\n          readOnly: true\n          subPath: entrypoint.sh\n      volumes:\n      - name: open-falcon-data\n        emptyDir: {}\n      - name: configmap-volume\n        configMap:\n          defaultMode: 0700\n          name: openfalcon-configmap\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: falcon-plus\n---\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  labels:\n    k8s-app: falcon-agent\n    kubernetes.io/cluster-service: 'true'\n    version: v1\n  name: falcon-agent\nspec:\n  revisionHistoryLimit: 10\n  selector:\n    matchLabels:\n      k8s-app: falcon-agent\n      kubernetes.io/cluster-service: 'true'\n      version: v1\n  template:\n    metadata:\n      creationTimestamp: null\n      labels:\n        k8s-app: falcon-agent\n        kubernetes.io/cluster-service: 'true'\n        version: v1\n    spec:\n      containers:\n        - args:\n            - '-c'\n            - /open-falcon/config/agent.json\n          command:\n            - ./agent/bin/falcon-agent\n          env:\n            - name: GIN_MODE\n              value: release\n            - name: NUX_ROOTFS\n              value: /rootfs\n            - name: FALCON_ENDPOINT\n              valueFrom:\n                fieldRef:\n                  apiVersion: v1\n                  fieldPath: spec.nodeName\n          image: 'openfalcon/falcon-plus:v0.3'\n          workingDir: /open-falcon\n          imagePullPolicy: IfNotPresent\n          name: falcon-agent\n          resources:\n            limits:\n              cpu: 200m\n              memory: 200Mi\n            requests:\n              cpu: 200m\n              memory: 200Mi\n          terminationMessagePath: /dev/termination-log\n          terminationMessagePolicy: File\n          volumeMounts:\n            - mountPath: /rootfs\n              name: rootfs\n              readOnly: true\n            - mountPath: /open-falcon/config\n              name: configmap-volume\n              readOnly: true\n      dnsPolicy: ClusterFirst\n      restartPolicy: Always\n      schedulerName: default-scheduler\n      securityContext: {}\n      serviceAccount: falcon-plus\n      serviceAccountName: falcon-plus\n      terminationGracePeriodSeconds: 30\n      volumes:\n        - hostPath:\n            path: /\n            type: ''\n          name: rootfs\n        - name: configmap-volume\n          configMap:\n            defaultMode: 0700\n            name: openfalcon-configmap\n  updateStrategy:\n    rollingUpdate:\n      maxUnavailable: 1\n    type: RollingUpdate"
  },
  {
    "path": "docker/k8s-example/redis.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: redis\n  labels:\n    app: db\nspec:\n  ports:\n    - port: 6379\n  selector:\n    app: db\n    name: redis\n---\napiVersion: extensions/v1beta1 \nkind: Deployment\nmetadata:\n  name: redis\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        app: db\n        name: redis\n    spec:\n      containers:\n      - image: redis:alpine\n        name: redis\n        livenessProbe:\n          tcpSocket:\n            port: 6379\n        ports:\n        - containerPort: 6379\n          name: redis\n"
  },
  {
    "path": "docker/mysql-init/Dockerfile",
    "content": "from alpine:3.5\n\nenv MYSQL_HOST=mysql \\\n    MYSQL_USER=root \\\n    MYSQL_PASSWORD=test123456\n\nrun apk add --no-cache mysql-client git\ncopy init_mysql_data.sh /\n\ncmd [\"/init_mysql_data.sh\"]\n"
  },
  {
    "path": "docker/mysql-init/init_mysql_data.sh",
    "content": "#!/bin/sh\n\nHost=${MYSQL_HOST}\nUser=${MYSQL_USER}\nPassword=${MYSQL_PASSWORD}\n\ncd /tmp && \\\n        git clone --depth=1 https://github.com/open-falcon/falcon-plus && \\\n        cd /tmp/falcon-plus/ && \\\n        for x in `ls ./scripts/mysql/db_schema/*.sql`; do\n            echo init mysql table $x ...;\n            mysql -h${Host} -u${User} -p${Password} < $x;\n        done\n\nrm -rf /tmp/falcon-plus/"
  },
  {
    "path": "docker/supervisord.conf",
    "content": "[supervisord]\nchildlogdir = /open-falcon/logs/\nlogfile = /open-falcon/logs/supervisord.log\npidfile = /var/run/supervisord.pid\nnodaemon = true\ndirectory = /open-falcon\n\n[unix_http_server]\nfile = /var/run/supervisor.sock\nchmod = 0777\nchown= nobody:nogroup\n\n[rpcinterface:supervisor]\nsupervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface\n\n[supervisorctl]\nserverurl = unix:///var/run/supervisor.sock\n\n[program:graph]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n[program:hbs]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n[program:judge]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n[program:transfer]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n[program:nodata]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n[program:aggregator]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n[program:agent]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n[program:gateway]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n[program:api]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n[program:alarm]\nuser = root\ndirectory = /open-falcon/%(program_name)s\ncommand = /open-falcon/%(program_name)s/bin/falcon-%(program_name)s -c /open-falcon/%(program_name)s/config/cfg.json\nstdout_logfile = /open-falcon/logs/%(program_name)s.log\nstderr_logfile = /open-falcon/logs/%(program_name)s.err\nautostart=false\n\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3.5'\n\nservices:\n  mysql:\n    container_name: falcon-mysql\n    image: mysql:5.7\n    environment:\n      MYSQL_ROOT_PASSWORD: root\n    volumes:\n      - ./scripts/mysql/db_schema:/docker-entrypoint-initdb.d/\n      - mysql-data:/var/lib/mysql\n\n  redis:\n    container_name: falcon-redis\n    image: redis:4-alpine3.8\n\n  hbs: &falcon\n    container_name: falcon-hbs\n    build:\n      context: ./\n      args:\n        MODULE: hbs\n      dockerfile: Dockerfile.module\n    image: openfalcon/falcon-hbs:dev\n    environment:\n      MYSQL_PORT: root:root@tcp\\(falcon-mysql:3306\\)\n      REDIS_PORT: falcon-redis:6379\n      AGGREGATOR_HTTP: falcon-aggregator:6055\n      GRAPH_HTTP: falcon-graph:6071\n      GRAPH_RPC: falcon-graph:6070\n      HBS_HTTP: falcon-hbs:6031\n      HBS_RPC: falcon-hbs:6030\n      JUDGE_HTTP: falcon-judge:6081\n      JUDGE_RPC: falcon-judge:6080\n      NODATA_HTTP: falcon-nodata:6090\n      TRANSFER_HTTP: falcon-transfer:6060\n      TRANSFER_RPC: falcon-transfer:8433\n      PLUS_API_HTTP: falcon-api:8080\n      AGENT_HOSTNAME: docker-agent\n    depends_on:\n      - mysql\n      - redis\n    command: \"sh ctrl.sh run hbs\"\n\n  agent:\n    <<: *falcon\n    build:\n      context: ./\n      args:\n        MODULE: agent\n      dockerfile: Dockerfile.module\n    image: openfalcon/falcon-agent:dev\n    container_name: falcon-agent\n    depends_on:\n      - hbs\n      - transfer\n    command: \"sh ctrl.sh run agent\"\n\n  aggregator:\n    <<: *falcon\n    build:\n      context: ./\n      args:\n        MODULE: aggregator\n      dockerfile: Dockerfile.module\n    image: openfalcon/falcon-aggregator:dev\n    container_name: falcon-aggregator\n    command: \"sh ctrl.sh run aggregator\"\n\n  nodata:\n    <<: *falcon\n    build:\n      context: ./\n      args:\n        MODULE: nodata\n      dockerfile: Dockerfile.module\n    image: openfalcon/falcon-nodata:dev\n    container_name: falcon-nodata\n    command: \"sh ctrl.sh run nodata\"\n\n  api:\n    <<: *falcon\n    build:\n      context: ./\n      args:\n        MODULE: api\n      dockerfile: Dockerfile.module\n    image: openfalcon/falcon-api:dev\n    container_name: falcon-api\n    command: \"sh ctrl.sh run api\"\n    ports:\n      - 8080:8080\n\n  alarm:\n    <<: *falcon\n    build:\n      context: ./\n      args:\n        MODULE: alarm\n      dockerfile: Dockerfile.module\n    image: openfalcon/falcon-alarm:dev\n    container_name: falcon-alarm\n    command: \"sh ctrl.sh run alarm\"\n\n  transfer:\n    <<: *falcon\n    build:\n      context: ./\n      args:\n        MODULE: transfer\n      dockerfile: Dockerfile.module\n    image: openfalcon/falcon-transfer:dev\n    container_name: falcon-transfer\n    depends_on:\n      - graph\n    command: \"sh ctrl.sh run transfer\"\n\n  judge:\n    <<: *falcon\n    build:\n      context: ./\n      args:\n        MODULE: judge\n      dockerfile: Dockerfile.module\n    image: openfalcon/falcon-judge:dev\n    container_name: falcon-judge\n    command: \"sh ctrl.sh run judge\"\n\n  graph:\n    <<: *falcon\n    build:\n      context: ./\n      args:\n        MODULE: graph\n      dockerfile: Dockerfile.module\n    image: openfalcon/falcon-graph:dev\n    container_name: falcon-graph\n    volumes:\n      - graph-data:/open-falcon/data\n    command: \"sh ctrl.sh run graph\"\n\n  dashboard:\n    container_name: falcon-dashboard\n    image: openfalcon/falcon-dashboard:v0.2.1\n    entrypoint: ./control startfg\n    environment:\n      API_ADDR: http://falcon-api:8080/api/v1\n      PORTAL_DB_HOST: mysql\n      PORTAL_DB_PORT: 3306\n      PORTAL_DB_USER: root\n      PORTAL_DB_PASS: root\n      PORTAL_DB_NAME: falcon_portal\n      ALARM_DB_HOST: mysql\n      ALARM_DB_PORT: 3306\n      ALARM_DB_USER: root\n      ALARM_DB_PASS: root\n      ALARM_DB_NAME: alarms\n    working_dir: /open-falcon/dashboard\n    ports:\n      - 8081:8081\n\nvolumes:\n  mysql-data:\n  graph-data:\n"
  },
  {
    "path": "docker_test.sh",
    "content": "#!/bin/bash\n\nexport DB_USER=root\nexport DB_PASSWORD=test123456\nexport DB_HOST=127.0.0.1\nexport DB_PORT=13306\nexport REDIS_HOST=127.0.0.1\nexport REDIS_PORT=16379\nexport API_PORT=18080\nexport API_HOST=127.0.0.1\n\ndocker rm -f falcon-mysql falcon-redis falcon-plus &> /dev/null\nif [[ `uname -m` == \"aarch64\" ]]; then\n\tdocker run --name falcon-mysql -e MYSQL_ROOT_PASSWORD=$DB_PASSWORD -p $DB_PORT:3306 -d mariadb:10.3\nelse\n\tdocker run --name falcon-mysql -e MYSQL_ROOT_PASSWORD=$DB_PASSWORD -p $DB_PORT:3306 -d mysql:5.7\nfi\ndocker run --name falcon-redis -p $REDIS_PORT:6379 -d redis:4-alpine3.8\n\necho \"waiting mysql start...\"\nsleep 15\nfor x in `ls ./scripts/mysql/db_schema/*.sql`; do\n    echo \"- - -\" $x ...\n    mysql -h $DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD < $x\ndone\n\ncommit_id=`git rev-parse --short HEAD`\nimage_tag=\"falcon-plus:$commit_id\"\n\n#build docker image from source code\nif [[ `uname -m` == \"aarch64\" ]]; then\n\tdocker build -t $image_tag -f Dockerfile_arm64 .\nelse\n\tdocker build -t $image_tag .\nfi\n\n## run falcon-plus container\ndocker run -itd --name falcon-plus \\\n\t --link=falcon-mysql:db.falcon \\\n\t --link=falcon-redis:redis.falcon \\\n\t -p 18433:8433 \\\n\t -p 18080:8080 \\\n\t -e MYSQL_PORT=$DB_USER:$DB_PASSWORD@tcp\\(db.falcon:3306\\) \\\n\t -e REDIS_PORT=redis.falcon:6379  \\\n\t $image_tag\nsleep 15\n\n## start falcon backend modules, such as graph,api,etc.\ndocker exec falcon-plus sh ctrl.sh start \\\n\t\tgraph hbs judge transfer nodata aggregator agent gateway api alarm\n\necho \"sleep 15s waiting for falcon-plus process ready...\"\nsleep 15\n\nmake test\n"
  },
  {
    "path": "docs/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) [year] [fullname]\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": "docs/Makefile",
    "content": "SRC = $(wildcard lib/*/*.js)\nHTML = $(wildcard lib/*/*.html)\nTEMPLATES = $(HTML:.html=.js)\nLESS = $(wildcard lib/*/*.less)\nCSS = $(LESS:.less=.css)\n\nbuild: components $(SRC) $(TEMPLATES) $(CSS)\n\t@component build --verbose --out . --name assets\n\ncomponents: component.json\n\t@component install\n\n%.js: %.html\n\t@component convert $<\n\n%.css: %.less\n\t@lessc $< $@\n\nclean:\n\trm -fr build components $(TEMPLATES)\n\n.PHONY: clean\n"
  },
  {
    "path": "docs/README.md",
    "content": "## The \"What ?\" and the \"Why ?\"\n\n**Carte** is a simple Jekyll based documentation website for APIs. It is designed as a boilerplate to build your own documentation and is heavily inspired from [Swagger](http://swagger.wordnik.com/) and [I/O docs](http://www.mashery.com/product/io-docs). Fork it, add specifications for your APIs calls and customize the theme. <small>Go ahead, see if we care.</small>\n\nWe built **Carte** because the existing options (Swagger and the likes) were trying to do too much and did not match our needs:\n\n1. Most of our API calls are sending JSON objects, as opposed to a series of parameters,\n1. Being able to query the real API is nice, but running anything but `GET` calls can get tricky (\"What do you mean I deleted my stuff? I was just trying out the API calls!\"),\n1. Overall, setting up a separate server for what really requires a good static documentation seemed overkill.\n\nThe real value of **Carte** is its structure for describing APIs, not its underlying technical stack (or lack-thereof). In a nutshell; **we built a static template for your API documentation, feel free to re-use it**.\n\n## Install\n\nIt' Jekyll god dammit:\n\n1. Clone this repository on your local,\n1. [Install Jekyll](https://github.com/mojombo/jekyll/wiki/install),\n1. Go at the root of the repository and run ```jekyll serve --watch```,\n1. Go to http://localhost:4000,\n1. [Great success! High five!](http://www.youtube.com/watch?v=wWWyJwHQ-4E)\n\n## How to...\n\n### Adding a new API call\n\nYou can add a new API call by simply adding a new post in the `_posts` folder. Jekyll by default forces you to specify a date in the file path: it makes us sad pandas too, but you'll have to stick to this format. You can use dates to control the order in which API calls are displayed in the interface.\n\nEach API call can define a few values in its YAML header:\n\nVariable | Mandatory | Default | Description\n--- | --- | --- | ---\n``title`` | Y | - | A short description of what that calls does.\n``path`` | N | - | The URL for the API call, including potential parameters.\n``type`` | N | - | Set it to `PUT`, `GET`, `POST`, `DELETE` or nothing (for parts of your documentation that do not relate to an actual API call).\n\nA typical header:\n\n```\n---\npath: '/stuff/:id'\ntitle: 'Delete a thing'\ntype: 'DELETE'\n\nlayout: nil\n---\n```\n\nWe then describe the request and response (or whatever else you wish to talk about) in the body of our post. Check the placeholders present in the `_posts` folder to get an idea of what it can look like.\n\n### Grouping calls\n\nAdding a category to your YAML header will allows you to group methods in the navigation. It is particularly helpful as you start having a lot of methods and need to organize them. For example:\n\n```\n---\ncategory: Stuff\npath: '/stuff/:id'\ntitle: 'Delete a thing'\ntype: 'DELETE'\n\nlayout: nil\n---\n```\n\n### Edit the design\n\nThe default UI is mostly described through the `css/style.css` file and a couple short jQuery scripts in the `/_layouts/default.html` layout. Hack it to oblivion.\n"
  },
  {
    "path": "docs/_config.yml",
    "content": "---\nexclude: ['README.markdown']\npermalink: ':title'\nsafe: false\ntitle: 'Falcon+ API'\nproject_name: 'Falcon+'\n"
  },
  {
    "path": "docs/_includes/nav.html",
    "content": "<h1>{{ site.title }}</h1>\n<ul id='links'>\n  {% for post in site.posts %}\n    {% if post.category == null %}\n    <li><a href='#{{ post.url }}'>{{ post.title }}</a></li>\n    {% endif %}\n  {% endfor %}\n  {% for category in site.categories %}\n  <li><h2>{{ category | first }}</h2>\n    <ul>\n    {% for posts in category %}\n      {% for post in posts %}        \n        <li class='{{ post.type }}'><a href='#{{ post.url }}'>{{ post.title }}</a></li>\n      {% endfor %}\n    {% endfor %}\n    </ul>\n  </li>\n{% endfor %}\n</ul>"
  },
  {
    "path": "docs/_layouts/default.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>{{ site.title }}</title>\n  <meta charset='utf-8'/>\n  <meta name='description' content='Documentation website'/>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'/>\n  <link href='assets.css' rel='stylesheet' type='text/css'>\n</head>\n<body>  \n  {{ content }}\n  \n  <!--[if lt IE 9]><script src='http://html5shim.googlecode.com/svn/trunk/html5.js'></script><![endif]-->\n  <script src='assets.js' type='text/javascript'></script>\n  <script>require('boot');</script>\n</body>\n</html>\n"
  },
  {
    "path": "docs/_posts/2017-01-01-authentication.md",
    "content": "---\ntitle: 'Auth Session'\napiurl: '/api/v1/user/auth_session'\ntype: 'GET'\nlayout: default\n---\n\n透过Session检查去判定使用者可否存取资源\n\n### RequestHeader\n透过RequestHeader 的 Apitoken做验证\n```\"RequestHeader\": {\n  \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n  \"X-Forwarded-For\": \" 127.0.0.1\"\n}```\n\n### Response\n\nSession 为有效\n```Status: 200```\n```{\"message\":\"session is vaild!\"}```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/2017-01-01-response-status-codes.md",
    "content": "---\ntitle: 'Response status codes'\n\nlayout: default\n---\n\n### Success\n\n* `POST`, `GET`, `PUT`, `DELETE` returns `200` on success,\n* 当参数使用不正确的时候会回覆 `400`\n\n### 参考\n\nreturn code 请参考 [status.go](https://golang.org/src/net/http/status.go)\n"
  },
  {
    "path": "docs/_posts/Admin/2017-01-01-admin_change_role.md",
    "content": "---\ncategory: Admin\napiurl: '/api/v1/admin/change_user_role'\ntitle: \"Change User's role\"\ntype: 'PUT'\nsample_doc: 'admin.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* `Admin` usage\n* admin:\n  * accept option:\n    * yes\n    * no\n\n### Request\n```{\"user_id\": 14, \"admin\": \"yes\"}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"user role update sccuessful, affect row: 1\"}```\n"
  },
  {
    "path": "docs/_posts/Admin/2017-01-01-admin_change_user_passwd.md",
    "content": "---\ncategory: Admin\napiurl: '/api/v1/admin/change_user_passwd'\ntitle: \"Change User's Password\"\ntype: 'PUT'\nsample_doc: 'admin.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* `Admin` usage\n\n### Request\n```{\"user_id\": 14, \"password\": \"newpasswd\"}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"password updated!\"}```\n"
  },
  {
    "path": "docs/_posts/Admin/2017-01-01-admin_delete_user.md",
    "content": "---\ncategory: Admin\napiurl: '/api/v1/admin/delete_user'\ntitle: 'Delete User'\ntype: 'DELETE'\nsample_doc: 'admin.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* `Admin` usage\n\n### Request\n```{\"user_id\": 31}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"user 31 has been delete, affect row: 1\"}```\n"
  },
  {
    "path": "docs/_posts/Admin/2017-12-07-admin_login.md",
    "content": "---\ncategory: Admin\napiurl: '/api/v1/admin/login'\ntitle: 'Admin Login'\ntype: 'POST'\nsample_doc: 'admin.html'\nlayout: default\n---\n\nSSO 登入\n\n* [Session](#/authentication) Required\n* `Admin` usage\n\n### Request\n```{\n  \"name\": \"test2\",\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"sig\": \"9d791331c0ea11e690c5001500c6ca5a\",\n  \"name\": \"test2\",\n  \"admin\": false\n}```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/Aggregator/2017-01-01-aggreator_create.md",
    "content": "---\ncategory: Aggregator\napiurl: '/api/v1/aggregator'\ntitle: \"Create Aggregator to a HostGroup\"\ntype: 'POST'\nsample_doc: 'aggregator.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* numerator: 分子\n* denominator: 分母\n* step: 汇报周期（秒为单位）\n\n### Request\n\n```{\n  \"tags\": \"\",\n  \"step\": 60,\n  \"numerator\": \"$(cpu.idle)\",\n  \"metric\": \"test.idle\",\n  \"hostgroup_id\": 343,\n  \"endpoint\": \"testenp\",\n  \"denominator\": \"2\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 16,\n  \"grp_id\": 343,\n  \"numerator\": \"$(cpu.idle)\",\n  \"denominator\": \"2\",\n  \"endpoint\": \"testenp\",\n  \"metric\": \"test.idle\",\n  \"tags\": \"\",\n  \"ds_type\": \"GAUGE\",\n  \"step\": 60,\n  \"creator\": \"root\"\n}```\n"
  },
  {
    "path": "docs/_posts/Aggregator/2017-01-01-aggreator_delete.md",
    "content": "---\ncategory: Aggregator\napiurl: '/api/v1/aggregator/16'\ntitle: \"Delete Aggregator\"\ntype: 'DELETE'\nsample_doc: 'aggregator.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```{\"message\":\"aggregator:16 is deleted\"}```\n"
  },
  {
    "path": "docs/_posts/Aggregator/2017-01-01-aggreator_of_hostgroup.md",
    "content": "---\ncategory: Aggregator\napiurl: '/api/v1/hostgroup/#{hostgroup_id}/aggregators'\ntitle: \"Get Aggregator List of HostGroup\"\ntype: 'GET'\nsample_doc: 'aggregator.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/hostgroup/343/aggregators\n* numerator: 分子\n* denominator: 分母\n* step: 汇报周期（秒为单位）\n\n### Response\n\n```Status: 200```\n```{\n  \"hostgroup\": \"test_group\",\n  \"aggregators\": [\n      {\n        \"id\": 13,\n        \"grp_id\": 343,\n        \"numerator\": \"$(cpu.idle)\",\n        \"denominator\": \"2\",\n        \"endpoint\": \"testenp\",\n        \"metric\": \"test.idle\",\n        \"tags\": \"\",\n        \"ds_type\": \"GAUGE\",\n        \"step\": 60,\n        \"creator\": \"root\"\n      },\n      {\n        \"id\": 14,\n        \"grp_id\": 343,\n        \"numerator\": \"$(cpu.idle)\",\n        \"denominator\": \"2\",\n        \"endpoint\": \"testenp\",\n        \"metric\": \"test.idle\",\n        \"tags\": \"\",\n        \"ds_type\": \"GAUGE\",\n        \"step\": 60,\n        \"creator\": \"root\"\n      }]\n}```\n"
  },
  {
    "path": "docs/_posts/Aggregator/2017-01-01-aggreator_update.md",
    "content": "---\ncategory: Aggregator\napiurl: '/api/v1/aggregators'\ntitle: \"Update Aggregator\"\ntype: 'PUT'\nsample_doc: 'aggregator.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* numerator: 分子\n* denominator: 分母\n* step: 汇报周期（秒为单位）\n\n### Request\n\n```{\n  \"tags\": \"\",\n  \"step\": 60,\n  \"numerator\": \"$(cpu.idle)\",\n  \"metric\": \"test.idle\",\n  \"id\": 16,\n  \"endpoint\": \"testenp\",\n  \"denominator\": \"$#\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 16,\n  \"grp_id\": 343,\n  \"numerator\": \"$(cpu.idle)\",\n  \"denominator\": \"$#\",\n  \"endpoint\": \"testenp\",\n  \"metric\": \"test.idle\",\n  \"tags\": \"\",\n  \"ds_type\": \"GAUGE\",\n  \"step\": 60,\n  \"creator\": \"root\"\n}```\n"
  },
  {
    "path": "docs/_posts/Aggregator/2017-01-01-get_aggreator_by_id.md",
    "content": "---\ncategory: Aggregator\napiurl: '/api/v1/aggregators'\ntitle: \"Get Aggregator Info by id\"\ntype: 'GET'\nsample_doc: 'aggregator.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n```{\n  \"tags\": \"\",\n  \"step\": 60,\n  \"numerator\": \"$(cpu.idle)\",\n  \"metric\": \"test.idle\",\n  \"hostgroup_id\": 343,\n  \"endpoint\": \"testenp\",\n  \"denominator\": \"2\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 16,\n  \"grp_id\": 343,\n  \"numerator\": \"$(cpu.idle)\",\n  \"denominator\": \"2\",\n  \"endpoint\": \"testenp\",\n  \"metric\": \"test.idle\",\n  \"tags\": \"\",\n  \"ds_type\": \"GAUGE\",\n  \"step\": 60,\n  \"creator\": \"root\"\n}```\n"
  },
  {
    "path": "docs/_posts/Alarm/2017-01-01-alarm_eventcases_get_by_id.md",
    "content": "---\ncategory: Alarm\napiurl: '/api/v1/alarm/eventcases'\ntitle: 'Get EventCases by id'\ntype: 'GET'\nsample_doc: 'alarm.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\nContent-type: application/x-www-form-urlencoded\n\n```event_id=s_165_cef145900bf4e2a4a0db8b85762b9cdb ```\n\n### Response\n\n```Status: 200```\n```\n    [\n        {\n            \"closed_at\": null,\n            \"closed_note\": \"\",\n            \"cond\": \"0 != 66\",\n            \"current_step\": 3,\n            \"endpoint\": \"agent2\",\n            \"expression_id\": 0,\n            \"func\": \"all(#1)\",\n            \"id\": \"s_165_cef145900bf4e2a4a0db8b85762b9cdb\",\n            \"metric\": \"cpu.idle\",\n            \"note\": \"\\u5a13\\ue103\\u2502\\u935b\\u5a45\\ue11f\\u9477\\ue044\\u5aca\\u93c7\\u5b58\\u67ca\",\n            \"priority\": 0,\n            \"process_note\": 56603,\n            \"process_status\": \"ignored\",\n            \"status\": \"PROBLEM\",\n            \"step\": 300,\n            \"strategy_id\": 165,\n            \"template_id\": 45,\n            \"timestamp\": \"2017-03-23T15:51:11+08:00\",\n            \"tpl_creator\": \"root\",\n            \"update_at\": \"2016-06-23T05:00:00+08:00\",\n            \"user_modified\": 0\n        }\n    ]\n```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/Alarm/2017-01-01-alarm_eventcases_list.md",
    "content": "---\ncategory: Alarm\napiurl: '/api/v1/alarm/eventcases'\ntitle: 'EventCases List'\ntype: 'POST'\nsample_doc: 'alarm.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n```\n    {\n        \"endTime\": 1480521600,\n        \"limit\": 10,\n        \"process_status\": \"ignored,unresolved\",\n        \"startTime\": 1466956800,\n        \"status\": \"PROBLEM\",\n        \"endpoints\": [\"agent4\"],\n        \"strategy_id\": 46,\n        \"template_id\": 126\n    }\n```\n\n### Response\n\n```Status: 200```\n```\n    {\n        \"closed_at\": null,\n        \"closed_note\": \"\",\n        \"cond\": \"48.33759590792839 > 40\",\n        \"current_step\": 1,\n        \"endpoint\": \"agent4\",\n        \"expression_id\": 0,\n        \"func\": \"all(#3)\",\n        \"id\": \"s_46_1ac45122afb893adc02fbd30154ac303\",\n        \"metric\": \"cpu.iowait\",\n        \"note\": \"CPU I/O wait\\u74d2\\u5470\\u7e4340\",\n        \"priority\": 1,\n        \"process_note\": 16907,\n        \"process_status\": \"ignored\",\n        \"status\": \"PROBLEM\",\n        \"step\": 1,\n        \"strategy_id\": 46,\n        \"template_id\": 126,\n        \"timestamp\": \"2016-08-01T06:25:00+08:00\",\n        \"tpl_creator\": \"root\",\n        \"update_at\": \"2016-08-01T06:25:00+08:00\",\n        \"user_modified\": 0\n    }\n]\n```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/Alarm/2017-01-01-alarm_eventnote_create.md",
    "content": "---\ncategory: Alarm\napiurl: '/api/v1/alarm/event_note'\ntitle: 'Create Event Note'\ntype: 'POST'\nsample_doc: 'alarm.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n```\n    {\n        \"event_id\": \"s_165_cef145900bf4e2a4a0db8b85762b9cdb\",\n        \"note\": \"test note\",\n        \"status\": \"comment\"\n    }\n```\n\n### Response\n\n```Status: 200```\n```\n    {\n        \"id\": \"s_165_cef145900bf4e2a4a0db8b85762b9cdb\",\n        \"message\": \"add note to s_165_cef145900bf4e2a4a0db8b85762b9cdb successfuled\"\n    }\n```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/Alarm/2017-01-01-alarm_eventnote_get.md",
    "content": "---\ncategory: Alarm\napiurl: '/api/v1/alarm/event_note'\ntitle: 'Get Event Note by id or time range'\ntype: 'GET'\nsample_doc: 'alarm.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\nContent-type: application/x-www-form-urlencoded\n```endTime=1466697600&startTime=1466611200```\nor\n```event_id=s_165_cef145900bf4e2a4a0db8b85762b9cdb```\n\n\n### Response\n\n```Status: 200```\n```\n    [\n        {\n            \"case_id\": \"\",\n            \"event_caseId\": \"s_165_cef145900bf4e2a4a0db8b85762b9cdb\",\n            \"note\": \"test\",\n            \"status\": \"ignored\",\n            \"timestamp\": \"2016-06-23T05:39:09+08:00\",\n            \"user\": \"root\"\n        },\n        {\n            \"case_id\": \"\",\n            \"event_caseId\": \"s_165_9d223f126e7ecb3477cd6806f1ee9656\",\n            \"note\": \"Ignored by user\",\n            \"status\": \"ignored\",\n            \"timestamp\": \"2016-06-23T05:38:56+08:00\",\n            \"user\": \"root\"\n        }\n    ]\n```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/Alarm/2017-01-01-alarm_events_create.md",
    "content": "---\ncategory: Alarm\napiurl: '/api/v1/alarm/events'\ntitle: 'Create Events'\ntype: 'POST'\nsample_doc: 'alarm.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\nContent-type: application/x-www-form-urlencoded\n\nKey|Value\n---|---\nendTime|1466628960\nevent_id|s_165_cef145900bf4e2a4a0db8b85762b9cdb\nstartTime|1466611200\n\n### Response\n\n```Status: 200```\n```\n    [\n        {\n            \"cond\": \"10.649350649350648 != 66\",\n            \"event_caseId\": \"s_165_cef145900bf4e2a4a0db8b85762b9cdb\",\n            \"id\": 635166,\n            \"status\": 0,\n            \"step\": 0,\n            \"timestamp\": \"2016-06-23T04:55:00+08:00\"\n        },\n        {\n            \"cond\": \"13.486005089058525 != 66\",\n            \"event_caseId\": \"s_165_cef145900bf4e2a4a0db8b85762b9cdb\",\n            \"id\": 635149,\n            \"status\": 0,\n            \"step\": 0,\n            \"timestamp\": \"2016-06-23T04:50:00+08:00\"\n        }\n    ]\n```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardGraph/2017-01-01-dashboard_graph_create.md",
    "content": "---\ncategory: DashboardGraph\napiurl: '/api/v1/dashboard/graph'\ntitle: 'Create User'\ntype: 'POST'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n```\n{\n    \"screen_id\": 953,\n    \"title\": \"laiwei-test-graph1\",\n    \"endpoints\": [\"laiweiofficemac\"],\n    \"counters\": [\"value/name=pfc.push.ms\",\"value/name=pfc.push.size\"],\n    \"timespan\": 1800, \n    \"graph_type\": \"h\", \n    \"method\": \"AVG\",\n    \"position\": 0\n}\n```\n\n### Response\n\n```Status: 200```\n\n```{\"message\":\"ok\"}```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardGraph/2017-01-01-dashboard_graph_create_tmpgraph.md",
    "content": "---\ncategory: DashboardGraph\napiurl: '/api/v1/dashboard/tmpgraph'\ntitle: 'Create a tmpgraph'\ntype: 'POST'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n``` {\"endpoints\":[\"e1\", \"e2\"], \"counters\":[\"c1\", \"c2\"]} ```\n\n### Response\n\n```Status: 200```\n\n```\n{\n    \"ck\": \"68c07419dbd7ac65977c97d05d99440d\",\n    \"counters\": \"c1|c2\",\n    \"endpoints\": \"e1|e2\",\n    \"id\": 365195\n}\n```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardGraph/2017-01-01-dashboard_graph_delete.md",
    "content": "---\ncategory: DashboardGraph\napiurl: '/api/v1/dashboard/graph/:id'\ntitle: 'Delete a DashboardGraph'\ntype: 'DELETE'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n\n```{\"message\":\"ok\"}```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardGraph/2017-01-01-dashboard_graph_get.md",
    "content": "---\ncategory: DashboardGraph\napiurl: '/api/v1/dashboard/graph/:id'\ntitle: 'Get DashboardGraph info by id'\ntype: 'GET'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```\n{\n    \"counters\":[\"value/name=pfc.push.ms\", \"value/name=pfc.push.size\"],\n    \"endpoints\":[\"laiweiofficemac\"],\n    \"falcon_tags\":\"\",\n    \"graph_id\":4626,\n    \"graph_type\":\"h\",\n    \"method\":\"\",\n    \"position\":4626,\n    \"screen_id\":953,\n    \"timespan\":3600,\n    \"title\":\"test\"\n}```\n\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardGraph/2017-01-01-dashboard_graph_get_tmpgraph_by_id.md",
    "content": "---\ncategory: DashboardGraph\napiurl: '/api/v1/dashboard/tmpgraph/:id'\ntitle: 'Get a tmpgraph by id'\ntype: 'GET'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n\n```{\"counters\":[\"agent.alive\"],\"endpoints\":[\"laiweiofficemac\"]}```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardGraph/2017-01-01-dashboard_graph_update.md",
    "content": "---\ncategory: DashboardGraph\napiurl: '/api/v1/dashboard/graph/:id'\ntitle: 'Update a DashboardGraph'\ntype: 'PUT'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n```\n{\n    \"counters\": [\"value/name=pfc.push.ms\",\"value/name=pfc.push.size\", \"agent.alive\"],\n    \"falcon_tags\": \"srv=falcon\"\n}\n```\n\n### Response\n\n```Status: 200```\n\n```{\"message\":\"ok\"}```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardGraph/2017-01-01-dashboard_graphs_gets_by_screenid.md",
    "content": "---\ncategory: DashboardGraph\napiurl: '/api/v1/dashboard/graphs/screen/:screen_id'\ntitle: 'Gets graphs by screen id'\ntype: 'GET'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n\n```\n[\n    {\n        \"counters\": [\n            \"value/name=pfc.push.ms\"\n        ],\n        \"endpoints\": [\n            \"laiweiofficemac\"\n        ],\n        \"falcon_tags\": \"\",\n        \"graph_id\": 4640,\n        \"graph_type\": \"h\",\n        \"method\": \"\",\n        \"position\": 0,\n        \"screen_id\": 991,\n        \"timespan\": 3600,\n        \"title\": \"dddd\"\n    },\n    {\n        \"counters\": [\n            \"aaa\"\n        ],\n        \"endpoints\": [\n            \"xxx\"\n        ],\n        \"falcon_tags\": \"\",\n        \"graph_id\": 4641,\n        \"graph_type\": \"h\",\n        \"method\": \"SUM\",\n        \"position\": 0,\n        \"screen_id\": 991,\n        \"timespan\": 3600,\n        \"title\": \"dddd\"\n    }\n]\n```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardScreen/2017-01-01-dashboard_screen_create.md",
    "content": "---\ncategory: DashboardScreen\napiurl: '/api/v1/dashboard/screen'\ntitle: 'Create a DashboardScreen'\ntype: 'POST'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\nContent-type: application/x-www-form-urlencoded\n\n```name=laiwei-sceen1&pid=0```\n\n### Response\n\n```Status: 200```\n```{\"name\":\"laiwei-sceen1\",\"pid\":0,\"screen_id\":961} ```\n\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardScreen/2017-01-01-dashboard_screen_delete.md",
    "content": "---\ncategory: DashboardScreen\napiurl: '/api/v1/dashboard/screen/:screen_id'\ntitle: 'Delete a DashboardScreen'\ntype: 'DELETE'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```{\"message\":\"ok\"} ```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardScreen/2017-01-01-dashboard_screen_get_by_id.md",
    "content": "---\ncategory: DashboardScreen\napiurl: '/api/v1/dashboard/screen/:screen_id'\ntitle: 'Get a DashboardScreen by id'\ntype: 'GET'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```{\"id\":961,\"pid\":0,\"name\":\"laiwei-sceen1\"} ```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardScreen/2017-01-01-dashboard_screen_gets_all.md",
    "content": "---\ncategory: DashboardScreen\napiurl: '/api/v1/dashboard/screens'\ntitle: 'Gets all DashboardScreens'\ntype: 'GET'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\nContent-type: application/x-www-form-urlencoded\n\n* params:\n  * limit: 【选填】查询最大数据量，默认值：500，如：limit=10 只查询最多10条数据\n\n### Response\n```Status: 200```\n\n```\n[\n    {\n        \"id\": 952,\n        \"name\": \"a1\",\n        \"pid\": 0\n    },\n    {\n        \"id\": 953,\n        \"name\": \"aa1\",\n        \"pid\": 952\n    },\n    {\n        \"id\": 968,\n        \"name\": \"laiwei-screen2\",\n        \"pid\": 1\n    },\n    {\n        \"id\": 972,\n        \"name\": \"laiwei-sceen1\",\n        \"pid\": 0\n    },\n    {\n        \"id\": 991,\n        \"name\": \"xnew\",\n        \"pid\": 972\n    },\n    {\n        \"id\": 993,\n        \"name\": \"clone3\",\n        \"pid\": 972\n    },\n    {\n        \"id\": 995,\n        \"name\": \"op\",\n        \"pid\": 0\n    }\n]\n```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardScreen/2017-01-01-dashboard_screen_gets_by_pid.md",
    "content": "---\ncategory: DashboardScreen\napiurl: '/api/v1/dashboard/screens/pid/:screen_pid'\ntitle: 'Gets DashboardScreens by pid'\ntype: 'GET'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```\n[\n    {\n        \"id\": 952,\n        \"name\": \"a1\",\n        \"pid\": 0\n    },\n    {\n        \"id\": 961,\n        \"name\": \"laiwei-sceen1\",\n        \"pid\": 0\n    }\n]\n```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/DashboardScreen/2017-01-01-dashboard_screen_update.md",
    "content": "---\ncategory: DashboardScreen\napiurl: '/api/v1/dashboard/screen/:screen_id'\ntitle: 'Update a DashboardScreen'\ntype: 'PUT'\nsample_doc: 'dashboard.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\nContent-type: application/x-www-form-urlencoded\n\n```name=laiwei-sceen1&pid=0```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"ok\"} ```\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/Expression/2017-01-01-expression_create.md",
    "content": "---\ncategory: Expression\napiurl: '/api/v1/expression'\ntitle: \"Create Expression\"\ntype: 'POST'\nsample_doc: 'expression.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n```{\n  \"right_value\": \"0\",\n  \"priority\": 2,\n  \"pause\": 0,\n  \"op\": \"==\",\n  \"note\": \"this is a test exp\",\n  \"max_step\": 3,\n  \"func\": \"all(#3)\",\n  \"expression\": \"each(metric=agent.alive endpoint=docker-agent)\",\n  \"action\": {\n    \"url\": \"http://localhost:1234/callback\",\n    \"uic\": [\n      \"test\"\n    ],\n    \"callback\": 1,\n    \"before_callback_sms\": 1,\n    \"before_callback_mail\": 0,\n    \"after_callback_sms\": 1,\n    \"after_callback_mail\": 0\n  }\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"expression created\"}```\n"
  },
  {
    "path": "docs/_posts/Expression/2017-01-01-expression_delete.md",
    "content": "---\ncategory: Expression\napiurl: '/api/v1/expression/#{expression_id}'\ntitle: \"Delete Expression\"\ntype: 'DELETE'\nsample_doc: 'expression.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/expression/5\n\n### Response\n\n```Status: 200```\n```{\"message\":\"expression:5 has been deleted\"}```\n"
  },
  {
    "path": "docs/_posts/Expression/2017-01-01-expression_info_by_id.md",
    "content": "---\ncategory: Expression\napiurl: '/api/v1/expression/#{expression_id}'\ntitle: \"Get Expression Info by id\"\ntype: 'GET'\nsample_doc: 'expression.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\nex. /api/v1/expression/5\n\n\n### Response\n\n```Status: 200```\n```{\n  \"action\": {\n    \"id\": 5,\n    \"uic\": \"taipei\",\n    \"url\": \"\",\n    \"callback\": 0,\n    \"before_callback_sms\": 0,\n    \"before_callback_mail\": 0,\n    \"after_callback_sms\": 0,\n    \"after_callback_mail\": 0\n  },\n  \"expression\": {\n    \"id\": 5,\n    \"expression\": \"each(metric=agent.alive endpoint=docker-agent)\",\n    \"func\": \"all(#3)\",\n    \"op\": \"==\",\n    \"right_value\": \"0\",\n    \"max_step\": 3,\n    \"priority\": 2,\n    \"note\": \"this is a test exp\",\n    \"action_id\": 177,\n    \"create_user\": \"root\",\n    \"pause\": 1\n  }\n}```\n"
  },
  {
    "path": "docs/_posts/Expression/2017-01-01-expression_list.md",
    "content": "---\ncategory: Expression\napiurl: '/api/v1/expression'\ntitle: \"Expression List\"\ntype: 'GET'\nsample_doc: 'expression.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 2,\n    \"expression\": \"each(metric=? xx=yy)\",\n    \"func\": \"all(#3)\",\n    \"op\": \"==\",\n    \"right_value\": \"0\",\n    \"max_step\": 3,\n    \"priority\": 0,\n    \"note\": \"\",\n    \"action_id\": 18,\n    \"create_user\": \"root\",\n    \"pause\": 0\n  },\n  {\n    \"id\": 3,\n    \"expression\": \"each(metric=ss.close.wait endpoint=docker-A)\",\n    \"func\": \"all(#1)\",\n    \"op\": \"!=\",\n    \"right_value\": \"0\",\n    \"max_step\": 1,\n    \"priority\": 4,\n    \"note\": \"boss docker-A 连接数大于10\",\n    \"action_id\": 91,\n    \"create_user\": \"root\",\n    \"pause\": 0\n  },\n  {\n    \"id\": 4,\n    \"expression\": \"each(metric=agent.alive endpoint=docker-agent)\",\n    \"func\": \"all(#3)\",\n    \"op\": \"==\",\n    \"right_value\": \"0\",\n    \"max_step\": 3,\n    \"priority\": 2,\n    \"note\": \"this is a test exp\",\n    \"action_id\": 176,\n    \"create_user\": \"root\",\n    \"pause\": 1\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/Expression/2017-01-01-expression_update.md",
    "content": "---\ncategory: Expression\napiurl: '/api/v1/expression'\ntitle: \"Update Expression\"\ntype: 'PUT'\nsample_doc: 'expression.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n```{\n  \"right_value\": \"0\",\n  \"priority\": 2,\n  \"pause\": 1,\n  \"op\": \"==\",\n  \"note\": \"this is a test exp\",\n  \"max_step\": 3,\n  \"id\": 5,\n  \"func\": \"all(#3)\",\n  \"expression\": \"each(metric=agent.alive endpoint=docker-agent)\",\n  \"action\": {\n    \"url\": \"http://localhost:1234/callback\",\n    \"uic\": [\n      \"test\",\n      \"test2\"\n    ],\n    \"callback\": 0,\n    \"before_callback_sms\": 1,\n    \"before_callback_mail\": 0,\n    \"after_callback_sms\": 1,\n    \"after_callback_mail\": 0\n  }\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"expression:5 has been updated\"}```\n"
  },
  {
    "path": "docs/_posts/Graph/2017-01-01-endpoint_counter.md",
    "content": "---\ncategory: Graph\napiurl: '/api/v1/graph/endpoint_counter'\ntitle: \"Get Counter of Endpoint\"\ntype: 'GET'\nsample_doc: 'graph.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* params:\n  * eid: endpoint id list\n  * metricQuery: 查询counter参数【选填】。如：metricQuery=device=sda\n  * page: 【选填】分页查询的页码，默认值：1,如： page=2 表示第2页\n  * limit: 【选填】分页查询的页大小，默认值：500，如：limit=10 表示每页10条数据\n  * q: 使用 regex 查询字符\n    * option 参数\n\n### Response\n\n```Status: 200```\n```[\n  \"disk.io.avgqu-sz/device=sda\",\n  \"disk.io.ios_in_progress/device=sda\",\n  \"disk.io.msec_read/device=sda\",\n  \"disk.io.read_requests/device=sda\",\n  ...\n]```\n"
  },
  {
    "path": "docs/_posts/Graph/2017-01-01-endpoints.md",
    "content": "---\ncategory: Graph\napiurl: '/api/v1/graph/endpoint'\ntitle: \"Endpoint List\"\ntype: 'GET'\nsample_doc: 'graph.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* params:\n    * q: 使用 regex 查询字符\n      * option 参数\n    * page: 【选填】分页查询的页码，默认值：1,如： page=2 表示第2页\n    * limit: 【选填】分页查询的页大小，默认值：500，如：limit=10 表示每页10条数据\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"endpoint\": \"docker-agent\",\n    \"id\": 7\n  },\n  {\n    \"endpoint\": \"docker-task\",\n    \"id\": 6\n  },\n  {\n    \"endpoint\": \"graph\",\n    \"id\": 3\n  },\n  {\n    \"endpoint\": \"nodata\",\n    \"id\": 920\n  },\n  {\n    \"endpoint\": \"task\",\n    \"id\": 5\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/Graph/2017-01-01-grafana.md",
    "content": "---\ncategory: Graph\napiurl: '/v1/grafana/render'\ntitle: \"Grafan query\"\ntype: 'POST'\nlayout: default\n---\n\n* target: grafana query查询串 (type: []string)\n  * 支援多组查询条件.\n  * ex. [\"{host-A}#cpu#idel\", \"{1.1.1.1,2.2.2.2,3.3.3.3}#cpu#idle\"]\n  * 為了支援ip & 一些实做的限制. 所以将 \".\" 制换成 \"#\"\n  * {}# 后面代入的的counter 会作為查询counter的依据. 可以支援regex match. 例如 #.+cpu.+ 会将所有包含cpu字眼的counter一并查询返回数据画图\n  * 有时想要找特定的counter可以善用regex语法 \"^\" or \"$\" 去限定字串的范围 ex. [\"{host-A}#^cpu#idel$\"]\n  * 这边保留很大的弹性, 有特殊需求的可以自行修改判断逻辑\n* from: start time (unix time)\n* until: end time (unix time)\n* step: 查询graph时, 指定step interval\n  * default: 60\n* ConsolFun: 取样 -> [\"AVERAGE\", \"MAX\", \"MIN\"]\n  * default: \"AVERAGE\"\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"endpoint\": \"host-A\",\n    \"counter\": \"cpu.idle\",\n    \"dstype\": \"GAUGE\",\n    \"step\": 60,\n    \"Values\": [\n      {\n          \"timestamp\": 1506698040,\n          \"value\": 55.934343\n      },\n      {\n          \"timestamp\": 1506698100,\n          \"value\": 44.656489\n      }\n    ]\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/Graph/2017-01-01-graph_histroy.md",
    "content": "---\ncategory: Graph\napiurl: '/api/v1/graph/history'\ntitle: \"Graph History\"\ntype: 'POST'\nsample_doc: 'graph.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* dashobard 画图资料\n* consol_fun:\n  * AVERAGE\n  * MAX\n  * MIN\n\n### Request\n```{\n  \"step\": 60,\n  \"start_time\": 1481854596,\n  \"hostnames\": [\n    \"docker-a\",\n    \"docker-b\",\n    \"docker-c\"\n  ],\n  \"end_time\": 1481858193,\n  \"counters\": [\n    \"cpu.idle\",\n    \"cpu.iowait\"\n  ],\n  \"consol_fun\": \"AVERAGE\"\n}```\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"endpoint\": \"docker-a\",\n    \"counter\": \"cpu.idle\",\n    \"dstype\": \"GAUGE\",\n    \"step\": 60,\n    \"Values\": [\n      {\n        \"timestamp\": 1481854620,\n        \"value\": 98.154506\n      },\n      {\n        \"timestamp\": 1481854680,\n        \"value\": 97.864161\n      },\n      {\n        \"timestamp\": 1481854740,\n        \"value\": 97.521368\n      },\n      {\n        \"timestamp\": 1481854800,\n        \"value\": 97.587247\n      },\n      {\n        \"timestamp\": 1481854860,\n        \"value\": 97.440273\n      },\n      {\n        \"timestamp\": 1481854920,\n        \"value\": 97.914006\n      },\n      {\n        \"timestamp\": 1481854980,\n        \"value\": 97.223409\n      },\n      {\n        \"timestamp\": 1481855040,\n        \"value\": 98.029135\n      },\n      {\n        \"timestamp\": 1481855100,\n        \"value\": 97.614991\n      },\n      {\n        \"timestamp\": 1481855160,\n        \"value\": 97.565143\n      },\n      {\n        \"timestamp\": 1481855220,\n        \"value\": 97.070064\n      },\n      {\n        \"timestamp\": 1481855280,\n        \"value\": 98.726115\n      },\n      {\n        \"timestamp\": 1481855340,\n        \"value\": 98.720137\n      },\n      {\n        \"timestamp\": 1481855400,\n        \"value\": 98.205128\n      },\n      {\n        \"timestamp\": 1481855460,\n        \"value\": 97.70017\n      },\n      {\n        \"timestamp\": 1481855520,\n        \"value\": 97.780623\n      },\n      {\n        \"timestamp\": 1481855580,\n        \"value\": 97.379725\n      },\n      {\n        \"timestamp\": 1481855640,\n        \"value\": 98.034188\n      },\n      {\n        \"timestamp\": 1481855700,\n        \"value\": 98.246364\n      },\n      {\n        \"timestamp\": 1481855760,\n        \"value\": 98.372591\n      },\n      {\n        \"timestamp\": 1481855820,\n        \"value\": 98.152921\n      },\n      {\n        \"timestamp\": 1481855880,\n        \"value\": 97.914006\n      },\n      {\n        \"timestamp\": 1481855940,\n        \"value\": 95.592048\n      },\n      {\n        \"timestamp\": 1481856000,\n        \"value\": 94.11512\n      },\n      {\n        \"timestamp\": 1481856060,\n        \"value\": 97.596567\n      },\n      {\n        \"timestamp\": 1481856120,\n        \"value\": 97.501077\n      },\n      {\n        \"timestamp\": 1481856180,\n        \"value\": 96.374622\n      },\n      {\n        \"timestamp\": 1481856240,\n        \"value\": 89.570815\n      },\n      {\n        \"timestamp\": 1481856300,\n        \"value\": 96.410035\n      },\n      {\n        \"timestamp\": 1481856360,\n        \"value\": 97.567222\n      },\n      {\n        \"timestamp\": 1481856420,\n        \"value\": 97.25204\n      },\n      {\n        \"timestamp\": 1481856480,\n        \"value\": 95.356836\n      },\n      {\n        \"timestamp\": 1481856540,\n        \"value\": 97.330508\n      },\n      {\n        \"timestamp\": 1481856600,\n        \"value\": 96.999571\n      },\n      {\n        \"timestamp\": 1481856660,\n        \"value\": 97.278912\n      },\n      {\n        \"timestamp\": 1481856720,\n        \"value\": 97.229327\n      },\n      {\n        \"timestamp\": 1481856780,\n        \"value\": 97.212693\n      },\n      {\n        \"timestamp\": 1481856840,\n        \"value\": 96.503198\n      },\n      {\n        \"timestamp\": 1481856900,\n        \"value\": 96.790757\n      },\n      {\n        \"timestamp\": 1481856960,\n        \"value\": 98.121264\n      },\n      {\n        \"timestamp\": 1481857020,\n        \"value\": 98.550725\n      },\n      {\n        \"timestamp\": 1481857080,\n        \"value\": 97.548387\n      },\n      {\n        \"timestamp\": 1481857140,\n        \"value\": 98.466127\n      },\n      {\n        \"timestamp\": 1481857200,\n        \"value\": 97.9006\n      },\n      {\n        \"timestamp\": 1481857260,\n        \"value\": 97.985426\n      },\n      {\n        \"timestamp\": 1481857320,\n        \"value\": 97.357204\n      },\n      {\n        \"timestamp\": 1481857380,\n        \"value\": 97.086547\n      },\n      {\n        \"timestamp\": 1481857440,\n        \"value\": 98.770144\n      },\n      {\n        \"timestamp\": 1481857500,\n        \"value\": 97.727273\n      },\n      {\n        \"timestamp\": 1481857560,\n        \"value\": 98.595147\n      },\n      {\n        \"timestamp\": 1481857620,\n        \"value\": 97.867804\n      },\n      {\n        \"timestamp\": 1481857680,\n        \"value\": 98.128456\n      },\n      {\n        \"timestamp\": 1481857740,\n        \"value\": 97.886729\n      },\n      {\n        \"timestamp\": 1481857800,\n        \"value\": 95.969453\n      },\n      {\n        \"timestamp\": 1481857860,\n        \"value\": 97.134303\n      },\n      {\n        \"timestamp\": 1481857920,\n        \"value\": 98.033348\n      },\n      {\n        \"timestamp\": 1481857980,\n        \"value\": 96.511628\n      },\n      {\n        \"timestamp\": 1481858040,\n        \"value\": 96.522112\n      },\n      {\n        \"timestamp\": 1481858100,\n        \"value\": 97.49043\n      },\n      {\n        \"timestamp\": 1481858160,\n        \"value\": 96.958012\n      }\n    ]\n  },\n  {\n    \"endpoint\": \"docker-a\",\n    \"counter\": \"cpu.iowait\",\n    \"dstype\": \"GAUGE\",\n    \"step\": 60,\n    \"Values\": [\n      {\n        \"timestamp\": 1481854620,\n        \"value\": 0.815451\n      },\n      {\n        \"timestamp\": 1481854680,\n        \"value\": 0.598035\n      },\n      {\n        \"timestamp\": 1481854740,\n        \"value\": 1.239316\n      },\n      {\n        \"timestamp\": 1481854800,\n        \"value\": 0.775528\n      },\n      {\n        \"timestamp\": 1481854860,\n        \"value\": 0.895904\n      },\n      {\n        \"timestamp\": 1481854920,\n        \"value\": 0.893997\n      },\n      {\n        \"timestamp\": 1481854980,\n        \"value\": 0.811619\n      },\n      {\n        \"timestamp\": 1481855040,\n        \"value\": 0.728363\n      },\n      {\n        \"timestamp\": 1481855100,\n        \"value\": 0.425894\n      },\n      {\n        \"timestamp\": 1481855160,\n        \"value\": 0.768902\n      },\n      {\n        \"timestamp\": 1481855220,\n        \"value\": 1.443737\n      },\n      {\n        \"timestamp\": 1481855280,\n        \"value\": 0.29724\n      },\n      {\n        \"timestamp\": 1481855340,\n        \"value\": 0.213311\n      },\n      {\n        \"timestamp\": 1481855400,\n        \"value\": 0.512821\n      },\n      {\n        \"timestamp\": 1481855460,\n        \"value\": 1.022147\n      },\n      {\n        \"timestamp\": 1481855520,\n        \"value\": 0.810926\n      },\n      {\n        \"timestamp\": 1481855580,\n        \"value\": 0.515464\n      },\n      {\n        \"timestamp\": 1481855640,\n        \"value\": 0.555556\n      },\n      {\n        \"timestamp\": 1481855700,\n        \"value\": 0.470488\n      },\n      {\n        \"timestamp\": 1481855760,\n        \"value\": 0.428266\n      },\n      {\n        \"timestamp\": 1481855820,\n        \"value\": 0.386598\n      },\n      {\n        \"timestamp\": 1481855880,\n        \"value\": 0.63857\n      },\n      {\n        \"timestamp\": 1481855940,\n        \"value\": 0.432152\n      },\n      {\n        \"timestamp\": 1481856000,\n        \"value\": 0.730241\n      },\n      {\n        \"timestamp\": 1481856060,\n        \"value\": 0.643777\n      },\n      {\n        \"timestamp\": 1481856120,\n        \"value\": 0.603188\n      },\n      {\n        \"timestamp\": 1481856180,\n        \"value\": 1.035822\n      },\n      {\n        \"timestamp\": 1481856240,\n        \"value\": 8.927039\n      },\n      {\n        \"timestamp\": 1481856300,\n        \"value\": 0.605536\n      },\n      {\n        \"timestamp\": 1481856360,\n        \"value\": 0.341443\n      },\n      {\n        \"timestamp\": 1481856420,\n        \"value\": 0.343495\n      },\n      {\n        \"timestamp\": 1481856480,\n        \"value\": 0.601892\n      },\n      {\n        \"timestamp\": 1481856540,\n        \"value\": 0.466102\n      },\n      {\n        \"timestamp\": 1481856600,\n        \"value\": 0.557222\n      },\n      {\n        \"timestamp\": 1481856660,\n        \"value\": 0.382653\n      },\n      {\n        \"timestamp\": 1481856720,\n        \"value\": 0.554135\n      },\n      {\n        \"timestamp\": 1481856780,\n        \"value\": 0.428816\n      },\n      {\n        \"timestamp\": 1481856840,\n        \"value\": 1.151386\n      },\n      {\n        \"timestamp\": 1481856900,\n        \"value\": 0.556269\n      },\n      {\n        \"timestamp\": 1481856960,\n        \"value\": 0.469684\n      },\n      {\n        \"timestamp\": 1481857020,\n        \"value\": 0.29838\n      },\n      {\n        \"timestamp\": 1481857080,\n        \"value\": 0.903226\n      },\n      {\n        \"timestamp\": 1481857140,\n        \"value\": 0.426076\n      },\n      {\n        \"timestamp\": 1481857200,\n        \"value\": 0.771208\n      },\n      {\n        \"timestamp\": 1481857260,\n        \"value\": 1.071582\n      },\n      {\n        \"timestamp\": 1481857320,\n        \"value\": 1.278772\n      },\n      {\n        \"timestamp\": 1481857380,\n        \"value\": 0.642674\n      },\n      {\n        \"timestamp\": 1481857440,\n        \"value\": 0.212044\n      },\n      {\n        \"timestamp\": 1481857500,\n        \"value\": 0.686106\n      },\n      {\n        \"timestamp\": 1481857560,\n        \"value\": 0.425713\n      },\n      {\n        \"timestamp\": 1481857620,\n        \"value\": 0.810235\n      },\n      {\n        \"timestamp\": 1481857680,\n        \"value\": 0.765632\n      },\n      {\n        \"timestamp\": 1481857740,\n        \"value\": 0.380389\n      },\n      {\n        \"timestamp\": 1481857800,\n        \"value\": 0.296988\n      },\n      {\n        \"timestamp\": 1481857860,\n        \"value\": 0.855432\n      },\n      {\n        \"timestamp\": 1481857920,\n        \"value\": 0.470286\n      },\n      {\n        \"timestamp\": 1481857980,\n        \"value\": 1.248923\n      },\n      {\n        \"timestamp\": 1481858040,\n        \"value\": 1.631602\n      },\n      {\n        \"timestamp\": 1481858100,\n        \"value\": 1.531263\n      },\n      {\n        \"timestamp\": 1481858160,\n        \"value\": 0.599829\n      }\n    ]\n  },\n  {\n    \"endpoint\": \"docker-b\",\n    \"counter\": \"cpu.idle\",\n    \"dstype\": \"GAUGE\",\n    \"step\": 60,\n    \"Values\": [\n      {\n        \"timestamp\": 1481854620,\n        \"value\": 93.811775\n      },\n      {\n        \"timestamp\": 1481854680,\n        \"value\": 94.150538\n      },\n      {\n        \"timestamp\": 1481854740,\n        \"value\": 94.991438\n      },\n      {\n        \"timestamp\": 1481854800,\n        \"value\": 93.287435\n      },\n      {\n        \"timestamp\": 1481854860,\n        \"value\": 96.642584\n      },\n      {\n        \"timestamp\": 1481854920,\n        \"value\": 98.207426\n      },\n      {\n        \"timestamp\": 1481854980,\n        \"value\": 94.801875\n      },\n      {\n        \"timestamp\": 1481855040,\n        \"value\": 97.827939\n      },\n      {\n        \"timestamp\": 1481855100,\n        \"value\": 94.439692\n      },\n      {\n        \"timestamp\": 1481855160,\n        \"value\": 98.292787\n      },\n      {\n        \"timestamp\": 1481855220,\n        \"value\": 95.027624\n      },\n      {\n        \"timestamp\": 1481855280,\n        \"value\": 98.218074\n      },\n      {\n        \"timestamp\": 1481855340,\n        \"value\": 97.402044\n      },\n      {\n        \"timestamp\": 1481855400,\n        \"value\": 94.368601\n      },\n      {\n        \"timestamp\": 1481855460,\n        \"value\": 94.772631\n      },\n      {\n        \"timestamp\": 1481855520,\n        \"value\": 93.992331\n      },\n      {\n        \"timestamp\": 1481855580,\n        \"value\": 94.939446\n      },\n      {\n        \"timestamp\": 1481855640,\n        \"value\": 97.780623\n      },\n      {\n        \"timestamp\": 1481855700,\n        \"value\": 97.860505\n      },\n      {\n        \"timestamp\": 1481855760,\n        \"value\": 92.765411\n      },\n      {\n        \"timestamp\": 1481855820,\n        \"value\": 98.029979\n      },\n      {\n        \"timestamp\": 1481855880,\n        \"value\": 94.523502\n      },\n      {\n        \"timestamp\": 1481855940,\n        \"value\": 94.102564\n      },\n      {\n        \"timestamp\": 1481856000,\n        \"value\": 94.96587\n      },\n      {\n        \"timestamp\": 1481856060,\n        \"value\": 94.382979\n      },\n      {\n        \"timestamp\": 1481856120,\n        \"value\": 93.336181\n      },\n      {\n        \"timestamp\": 1481856180,\n        \"value\": 97.988875\n      },\n      {\n        \"timestamp\": 1481856240,\n        \"value\": 94.401709\n      },\n      {\n        \"timestamp\": 1481856300,\n        \"value\": 94.619983\n      },\n      {\n        \"timestamp\": 1481856360,\n        \"value\": 94.916702\n      },\n      {\n        \"timestamp\": 1481856420,\n        \"value\": 94.089733\n      },\n      {\n        \"timestamp\": 1481856480,\n        \"value\": 94.475375\n      },\n      {\n        \"timestamp\": 1481856540,\n        \"value\": 93.576017\n      },\n      {\n        \"timestamp\": 1481856600,\n        \"value\": 94.010195\n      },\n      {\n        \"timestamp\": 1481856660,\n        \"value\": 94.137783\n      },\n      {\n        \"timestamp\": 1481856720,\n        \"value\": 95.264505\n      },\n      {\n        \"timestamp\": 1481856780,\n        \"value\": 96.879008\n      },\n      {\n        \"timestamp\": 1481856840,\n        \"value\": 96.38759\n      },\n      {\n        \"timestamp\": 1481856900,\n        \"value\": 93.830334\n      },\n      {\n        \"timestamp\": 1481856960,\n        \"value\": 96.282051\n      },\n      {\n        \"timestamp\": 1481857020,\n        \"value\": 94.173093\n      },\n      {\n        \"timestamp\": 1481857080,\n        \"value\": 95.382642\n      },\n      {\n        \"timestamp\": 1481857140,\n        \"value\": 94.107452\n      },\n      {\n        \"timestamp\": 1481857200,\n        \"value\": 93.611584\n      },\n      {\n        \"timestamp\": 1481857260,\n        \"value\": 97.0538\n      },\n      {\n        \"timestamp\": 1481857320,\n        \"value\": 94.404101\n      },\n      {\n        \"timestamp\": 1481857380,\n        \"value\": 94.449189\n      },\n      {\n        \"timestamp\": 1481857440,\n        \"value\": 98.286938\n      },\n      {\n        \"timestamp\": 1481857500,\n        \"value\": 93.720632\n      },\n      {\n        \"timestamp\": 1481857560,\n        \"value\": 93.669803\n      },\n      {\n        \"timestamp\": 1481857620,\n        \"value\": 93.865294\n      },\n      {\n        \"timestamp\": 1481857680,\n        \"value\": 94.498934\n      },\n      {\n        \"timestamp\": 1481857740,\n        \"value\": 94.610778\n      },\n      {\n        \"timestamp\": 1481857800,\n        \"value\": 93.929029\n      },\n      {\n        \"timestamp\": 1481857860,\n        \"value\": 97.827939\n      },\n      {\n        \"timestamp\": 1481857920,\n        \"value\": 97.76824\n      },\n      {\n        \"timestamp\": 1481857980,\n        \"value\": 91.079014\n      },\n      {\n        \"timestamp\": 1481858040,\n        \"value\": 97.854998\n      },\n      {\n        \"timestamp\": 1481858100,\n        \"value\": 93.399482\n      },\n      {\n        \"timestamp\": 1481858160,\n        \"value\": 94.014536\n      }\n    ]\n  },\n  {\n    \"endpoint\": \"docker-b\",\n    \"counter\": \"cpu.iowait\",\n    \"dstype\": \"GAUGE\",\n    \"step\": 60,\n    \"Values\": [\n      {\n        \"timestamp\": 1481854620,\n        \"value\": 0.171895\n      },\n      {\n        \"timestamp\": 1481854680,\n        \"value\": 0.645161\n      },\n      {\n        \"timestamp\": 1481854740,\n        \"value\": 0.47089\n      },\n      {\n        \"timestamp\": 1481854800,\n        \"value\": 0.731497\n      },\n      {\n        \"timestamp\": 1481854860,\n        \"value\": 0.594985\n      },\n      {\n        \"timestamp\": 1481854920,\n        \"value\": 0.256082\n      },\n      {\n        \"timestamp\": 1481854980,\n        \"value\": 0.340861\n      },\n      {\n        \"timestamp\": 1481855040,\n        \"value\": 0.255537\n      },\n      {\n        \"timestamp\": 1481855100,\n        \"value\": 0.684346\n      },\n      {\n        \"timestamp\": 1481855160,\n        \"value\": 0.384123\n      },\n      {\n        \"timestamp\": 1481855220,\n        \"value\": 0.084998\n      },\n      {\n        \"timestamp\": 1481855280,\n        \"value\": 0.466695\n      },\n      {\n        \"timestamp\": 1481855340,\n        \"value\": 1.192504\n      },\n      {\n        \"timestamp\": 1481855400,\n        \"value\": 0.511945\n      },\n      {\n        \"timestamp\": 1481855460,\n        \"value\": 0.594985\n      },\n      {\n        \"timestamp\": 1481855520,\n        \"value\": 0.383468\n      },\n      {\n        \"timestamp\": 1481855580,\n        \"value\": 1.038062\n      },\n      {\n        \"timestamp\": 1481855640,\n        \"value\": 0.981647\n      },\n      {\n        \"timestamp\": 1481855700,\n        \"value\": 0.599059\n      },\n      {\n        \"timestamp\": 1481855760,\n        \"value\": 0.770548\n      },\n      {\n        \"timestamp\": 1481855820,\n        \"value\": 0.428266\n      },\n      {\n        \"timestamp\": 1481855880,\n        \"value\": 0.301854\n      },\n      {\n        \"timestamp\": 1481855940,\n        \"value\": 0.598291\n      },\n      {\n        \"timestamp\": 1481856000,\n        \"value\": 0.853242\n      },\n      {\n        \"timestamp\": 1481856060,\n        \"value\": 0.723404\n      },\n      {\n        \"timestamp\": 1481856120,\n        \"value\": 1.025203\n      },\n      {\n        \"timestamp\": 1481856180,\n        \"value\": 0.470689\n      },\n      {\n        \"timestamp\": 1481856240,\n        \"value\": 0.213675\n      },\n      {\n        \"timestamp\": 1481856300,\n        \"value\": 0.768574\n      },\n      {\n        \"timestamp\": 1481856360,\n        \"value\": 0.256301\n      },\n      {\n        \"timestamp\": 1481856420,\n        \"value\": 0.388266\n      },\n      {\n        \"timestamp\": 1481856480,\n        \"value\": 0.342612\n      },\n      {\n        \"timestamp\": 1481856540,\n        \"value\": 0.813704\n      },\n      {\n        \"timestamp\": 1481856600,\n        \"value\": 0.594732\n      },\n      {\n        \"timestamp\": 1481856660,\n        \"value\": 0.684638\n      },\n      {\n        \"timestamp\": 1481856720,\n        \"value\": 1.535836\n      },\n      {\n        \"timestamp\": 1481856780,\n        \"value\": 0.25652\n      },\n      {\n        \"timestamp\": 1481856840,\n        \"value\": 0.38249\n      },\n      {\n        \"timestamp\": 1481856900,\n        \"value\": 1.028278\n      },\n      {\n        \"timestamp\": 1481856960,\n        \"value\": 1.025641\n      },\n      {\n        \"timestamp\": 1481857020,\n        \"value\": 0.642674\n      },\n      {\n        \"timestamp\": 1481857080,\n        \"value\": 0.726806\n      },\n      {\n        \"timestamp\": 1481857140,\n        \"value\": 0.649913\n      },\n      {\n        \"timestamp\": 1481857200,\n        \"value\": 0.809199\n      },\n      {\n        \"timestamp\": 1481857260,\n        \"value\": 0.256191\n      },\n      {\n        \"timestamp\": 1481857320,\n        \"value\": 0.512601\n      },\n      {\n        \"timestamp\": 1481857380,\n        \"value\": 0.59778\n      },\n      {\n        \"timestamp\": 1481857440,\n        \"value\": 0.342612\n      },\n      {\n        \"timestamp\": 1481857500,\n        \"value\": 1.19607\n      },\n      {\n        \"timestamp\": 1481857560,\n        \"value\": 0.983747\n      },\n      {\n        \"timestamp\": 1481857620,\n        \"value\": 0.900901\n      },\n      {\n        \"timestamp\": 1481857680,\n        \"value\": 0.639659\n      },\n      {\n        \"timestamp\": 1481857740,\n        \"value\": 0.641574\n      },\n      {\n        \"timestamp\": 1481857800,\n        \"value\": 0.598546\n      },\n      {\n        \"timestamp\": 1481857860,\n        \"value\": 0.425894\n      },\n      {\n        \"timestamp\": 1481857920,\n        \"value\": 0.729614\n      },\n      {\n        \"timestamp\": 1481857980,\n        \"value\": 0.339847\n      },\n      {\n        \"timestamp\": 1481858040,\n        \"value\": 0.686401\n      },\n      {\n        \"timestamp\": 1481858100,\n        \"value\": 0.560828\n      },\n      {\n        \"timestamp\": 1481858160,\n        \"value\": 0.51304\n      }\n    ]\n  },\n  {\n    \"endpoint\": \"docker-c\",\n    \"counter\": \"cpu.idle\",\n    \"dstype\": \"\",\n    \"step\": 0,\n    \"Values\": []\n  },\n  {\n    \"endpoint\": \"docker-c\",\n    \"counter\": \"cpu.iowait\",\n    \"dstype\": \"\",\n    \"step\": 0,\n    \"Values\": []\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/Host/2017-01-01-host_maintain.md",
    "content": "---\ncategory: Host\napiurl: '/api/v1/host/maintain'\ntitle: \"Set host maintain by ids or hostnames\"\ntype: 'POST'\nsample_doc: 'host.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n```\n{\n    \"ids\": [1,2,3,4],\n    \"maintain_begin\": 1497951907,\n    \"maintain_end\": 1497951907\n}\n```\nor\n```\n{\n    \"hosts\": [\"host.a\",\"host.b\"],\n    \"maintain_begin\": 1497951907,\n    \"maintain_end\": 1497951907\n}\n```\n\n### Response\n\n```Status: 200```\n```{ \"message\": \"Through: hosts, Affect row: 2\" }```\n"
  },
  {
    "path": "docs/_posts/Host/2017-01-01-host_related_hostgroup.md",
    "content": "---\ncategory: Host\napiurl: '/api/v1/host/#{host_id}/hostgroup'\ntitle: \"Get related HostGorup of Host\"\ntype: 'GET'\nsample_doc: 'host.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/host/1647/hostgroup\n* grp_name: hostgroup name\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 78,\n    \"grp_name\": \"tplB\",\n    \"create_user\": \"userA\"\n  },\n  {\n    \"id\": 145,\n    \"grp_name\": \"Owl_Default_Group\",\n    \"create_user\": \"userA\"\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/Host/2017-01-01-host_related_template.md",
    "content": "---\ncategory: Host\napiurl: '/api/v1/host/#{host_id}/template'\ntitle: \"Get bind Template List of Host\"\ntype: 'GET'\nsample_doc: 'host.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/host/1647/template\n* tpl_name: template name\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 125,\n    \"tpl_name\": \"tplA\",\n    \"parent_id\": 0,\n    \"action_id\": 99,\n    \"create_user\": \"root\"\n  },\n  {\n    \"id\": 142,\n    \"tpl_name\": \"tplB\",\n    \"parent_id\": 0,\n    \"action_id\": 111,\n    \"create_user\": \"root\"\n  },\n  {\n    \"id\": 180,\n    \"tpl_name\": \"tplC\",\n    \"parent_id\": 0,\n    \"action_id\": 142,\n    \"create_user\": \"root\"\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/Host/2017-01-01-host_reset.md",
    "content": "---\ncategory: Host\napiurl: '/api/v1/host/maintain'\ntitle: \"Reset host maintain by ids or hostnames\"\ntype: 'DELETE'\nsample_doc: 'host.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n```{\"ids\": [1,2,3,4]}```\nor\n```{\"hosts\": [\"host.a\",\"host.b\"]}```\n\n### Response\n\n```Status: 200```\n```{ \"message\": \"Through: hosts, Affect row: 2\" }```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_add_host.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup/host'\ntitle: \"Add Hosts to HostGroup\"\ntype: 'POST'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* Hosts 每次会覆盖该HostGroup内现有的Host List\n* 如果使用者不是 Admin 只能对创建的hostgroup做操作\n\n### Request\n```{\n  \"hosts\": [\n    \"testhostgroup\",\n    \"agent_test\"\n  ],\n  \"hostgroup_id\": 343\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"[9312 9313] bind to hostgroup: 343\"}```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_create.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup'\ntitle: \"Create HostGroup\"\ntype: 'POST'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n```{\"name\":\"testhostgroup\"}```\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 343,\n  \"grp_name\": \"testhostgroup\",\n  \"create_user\": \"root\"\n}```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_delete.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup/#{hostgroup_id}'\ntitle: \"Delete HostGroup\"\ntype: 'DELETE'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\nex. /api/v1/hostgroup/343\n* 如果使用者不是 Admin 只能对创建的hostgroup做操作\n\n### Response\n\n```Status: 200```\n```{\"message\":\"hostgroup:343 has been deleted\"}```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_get_info_by_id.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup/#{hostgroup_id}'\ntitle: \"Get HostGroup info by id\"\ntype: 'GET'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/hostgroup/343\n\n### Response\n\n```Status: 200```\n```{\n  \"hostgroup\": {\n    \"id\": 343,\n    \"grp_name\": \"testhostgroup\",\n    \"create_user\": \"root\"\n  },\n  \"hosts\": [\n    {\n      \"id\": 9313,\n      \"hostname\": \"agent_test\",\n      \"ip\": \"\",\n      \"agent_version\": \"\",\n      \"plugin_version\": \"\",\n      \"maintain_begin\": 0,\n      \"maintain_end\": 0\n    }\n  ]\n}```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_list.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup'\ntitle: \"HostGroup List\"\ntype: 'GET'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 3,\n    \"grp_name\": \"docker-A\",\n    \"create_user\": \"user-A\"\n  },\n  {\n    \"id\": 5,\n    \"grp_name\": \"docker-T\",\n    \"create_user\": \"user-B\"\n  },\n  {\n    \"id\": 8,\n    \"grp_name\": \"docker-F\",\n    \"create_user\": \"root\"\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_template_bind.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup/template'\ntitle: \"Bind A Template to HostGroup\"\ntype: 'POST'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n```{\n  \"tpl_id\": 5,\n  \"grp_id\": 3\n}```\n\n### Response\n\n```Status: 200```\n```{\"grp_id\":3,\"tpl_id\":5,\"bind_user\":2}```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_template_list.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup/#{hostgroup_id}/template'\ntitle: \"Get Template List of  HostGroup\"\ntype: 'GET'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/hostgroup/3/template\n\n### Response\n\n```Status: 200```\n```{\n  \"hostgroup\": {\n    \"id\": 3,\n    \"grp_name\": \"hostgroupA\",\n    \"create_user\": \"root\"\n  },\n  \"templates\": [\n    {\n      \"id\": 5,\n      \"tpl_name\": \"TplA\",\n      \"parent_id\": 0,\n      \"action_id\": 12,\n      \"create_user\": \"root\"\n    },\n    {\n      \"id\": 91,\n      \"tpl_name\": \"TplB\",\n      \"parent_id\": 0,\n      \"action_id\": 59,\n      \"create_user\": \"userA\"\n    },\n    {\n      \"id\": 94,\n      \"tpl_name\": \"TplB\",\n      \"parent_id\": 0,\n      \"action_id\": 62,\n      \"create_user\": \"userA\"\n    },\n    {\n      \"id\": 103,\n      \"tpl_name\": \"TplC\",\n      \"parent_id\": 0,\n      \"action_id\": 74,\n      \"create_user\": \"root\"\n    },\n    {\n      \"id\": 104,\n      \"tpl_name\": \"TplD\",\n      \"parent_id\": 0,\n      \"action_id\": 75,\n      \"create_user\": \"root\"\n    },\n    {\n      \"id\": 105,\n      \"tpl_name\": \"TplE\",\n      \"parent_id\": 0,\n      \"action_id\": 76,\n      \"create_user\": \"root\"\n    },\n    {\n      \"id\": 116,\n      \"tpl_name\": \"TplG\",\n      \"parent_id\": 0,\n      \"action_id\": 87,\n      \"create_user\": \"root\"\n    },\n    {\n      \"id\": 125,\n      \"tpl_name\": \"TplH\",\n      \"parent_id\": 0,\n      \"action_id\": 99,\n      \"create_user\": \"root\"\n    },\n    {\n      \"id\": 126,\n      \"tpl_name\": \"http\",\n      \"parent_id\": 0,\n      \"action_id\": 100,\n      \"create_user\": \"root\"\n    },\n    {\n      \"id\": 127,\n      \"tpl_name\": \"TplJ\",\n      \"parent_id\": 0,\n      \"action_id\": 101,\n      \"create_user\": \"root\"\n    }\n  ]\n}```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_template_unbind.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup/template'\ntitle: \"Unbind A Template of A HostGroup\"\ntype: 'PUT'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n```{\n  \"tpl_id\": 5,\n  \"grp_id\": 3\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"template: 5 is unbind of HostGroup: 3\"}```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_unbind_host.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup/host'\ntitle: \"Unbind a Host on HostGroup\"\ntype: 'PUT'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* 如果使用者不是 Admin 只能对创建的hostgroup做操作\n\n### Request\n```{\n  \"hostgroup_id\": 343,\n  \"host_id\": 9312\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"unbind host:9312 of hostgroup: 343\"}```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-01-01-hostgroup_update.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup/update/#{hostgroup_id}'\ntitle: \"Update HostGroup info by id\"\ntype: 'PUT'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/hostgroup\n\n### Request\n```{\n  \"id\" : 343,\n  \"grp_name\": \"test1\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"message\":\"hostgroup profile updated\"\n}```\n"
  },
  {
    "path": "docs/_posts/HostGroup/2017-08-22-hostgroup_update_partial_hosts.md",
    "content": "---\ncategory: HostGroup\napiurl: '/api/v1/hostgroup/#{hostgroup_id}/host'\ntitle: \"Update partial hosts in HostGroup\"\ntype: 'PATCH'\nsample_doc: 'hostgroup.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* 如果使用者不是 Admin 只能对创建的 HostGroup 做操作\n* ex. /api/v1/hostgroup/1/host\n\n### Request\n```{\n  \"hosts\": [\n    \"host01\",\n    \"host02\"\n  ],\n  \"action\": \"add\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"message\": \"[host01, host02] bind to hostgroup: test, [] have been exist\"\n}```\n\n### Request\n```{\n  \"hosts\": [\n    \"host01\",\n    \"host02\"\n  ],\n  \"action\": \"remove\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"message\": \"[host01, host02] unbind to hostgroup: test\"\n}```\n\n"
  },
  {
    "path": "docs/_posts/NoData/2017-01-01-nodata_create.md",
    "content": "---\ncategory: NoData\napiurl: '/api/v1/nodata/'\ntitle: \"Create Nodata\"\ntype: 'POST'\nsample_doc: 'nodata.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n```{\n  \"tags\": \"\",\n  \"step\": 60,\n  \"obj_type\": \"host\",\n  \"obj\": \"docker-agent\",\n  \"name\": \"testnodata\",\n  \"mock\": -1,\n  \"metric\": \"test.metric\",\n  \"dstype\": \"GAUGE\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 4,\n  \"name\": \"testnodata\",\n  \"obj\": \"docker-agent\",\n  \"obj_type\": \"host\",\n  \"metric\": \"test.metric\",\n  \"tags\": \"\",\n  \"dstype\": \"GAUGE\",\n  \"step\": 60,\n  \"mock\": -1,\n  \"creator\": \"root\"\n}```\n"
  },
  {
    "path": "docs/_posts/NoData/2017-01-01-nodata_delete.md",
    "content": "---\ncategory: NoData\napiurl: '/api/v1/nodata/#{nodata_id}'\ntitle: \"Delete Nodata\"\ntype: 'DELETE'\nsample_doc: 'nodata.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/nodata/4\n\n### Response\n\n```Status: 200```\n```{\"message\":\"mockcfg:4 is deleted\"}```\n"
  },
  {
    "path": "docs/_posts/NoData/2017-01-01-nodata_info_by_id.md",
    "content": "---\ncategory: NoData\napiurl: '/api/v1/nodata/#{nodata_id}'\ntitle: \"Get Nodata Info by id\"\ntype: 'GET'\nsample_doc: 'nodata.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/nodata/2\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 2,\n  \"name\": \"owl_nodate\",\n  \"obj\": \"docker-agent\",\n  \"obj_type\": \"host\",\n  \"metric\": \"test.metric\",\n  \"tags\": \"\",\n  \"dstype\": \"GAUGE\",\n  \"step\": 60,\n  \"mock\": -2,\n  \"creator\": \"root\"\n}```\n"
  },
  {
    "path": "docs/_posts/NoData/2017-01-01-nodata_list.md",
    "content": "---\ncategory: NoData\napiurl: '/api/v1/nodata'\ntitle: \"Nodata List\"\ntype: 'GET'\nsample_doc: 'nodata.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 2,\n    \"name\": \"owl_nodate\",\n    \"obj\": \"docker-agent\",\n    \"obj_type\": \"host\",\n    \"metric\": \"test.metric\",\n    \"tags\": \"\",\n    \"dstype\": \"GAUGE\",\n    \"step\": 60,\n    \"mock\": -2,\n    \"creator\": \"root\"\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/NoData/2017-01-01-nodata_update.md",
    "content": "---\ncategory: NoData\napiurl: '/api/v1/nodata/'\ntitle: \"Update Nodata\"\ntype: 'PUT'\nsample_doc: 'nodata.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n\n```{\n  \"tags\": \"\",\n  \"step\": 60,\n  \"obj_type\": \"host\",\n  \"obj\": \"docker-agent\",\n  \"mock\": -2,\n  \"metric\": \"test.metric\",\n  \"id\": 4,\n  \"dstype\": \"GAUGE\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 0,\n  \"name\": \"\",\n  \"obj\": \"docker-agent\",\n  \"obj_type\": \"host\",\n  \"metric\": \"test.metric\",\n  \"tags\": \"\",\n  \"dstype\": \"GAUGE\",\n  \"step\": 60,\n  \"mock\": -2,\n  \"creator\": \"\"\n}```\n"
  },
  {
    "path": "docs/_posts/Plugin/2017-01-01-plugin_create.md",
    "content": "---\ncategory: Plugin\napiurl: '/api/v1/plugin'\ntitle: \"Create A Plugin of HostGroup\"\ntype: 'POST'\nsample_doc: 'plugin.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* grp_id: hostgroup id\n\n### Request\n\n```{\n  \"hostgroup_id\": 343,\n  \"dir_path\": \"testpath\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 1501,\n  \"grp_id\": 343,\n  \"dir\": \"testpath\",\n  \"create_user\": \"root\"\n}```\n"
  },
  {
    "path": "docs/_posts/Plugin/2017-01-01-plugin_delete.md",
    "content": "---\ncategory: Plugin\napiurl: '/api/v1/plugin/#{plugin_id}'\ntitle: \"Delete Plugin\"\ntype: 'DELETE'\nsample_doc: 'plugin.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/plugin/1501\n\n### Response\n\n```Status: 200```\n```{\"message\":\"plugin:1501 is deleted\"}```\n"
  },
  {
    "path": "docs/_posts/Plugin/2017-01-01-plugin_info_by_id.md",
    "content": "---\ncategory: Plugin\napiurl: '/api/v1/hostgroup/#{hostgroup_id}/plugins'\ntitle: \"Get Plugin List of HostGroup\"\ntype: 'GET'\nsample_doc: 'plugin.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/hostgroup/343/plugins\n* grp_id: hostgroup id\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 1499,\n    \"grp_id\": 343,\n    \"dir\": \"testpath\",\n    \"create_user\": \"root\"\n  },\n  {\n    \"id\": 1501,\n    \"grp_id\": 343,\n    \"dir\": \"testpath\",\n    \"create_user\": \"root\"\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/Strategy/2017-01-01-metric_tmplist.md",
    "content": "---\ncategory: Metric\napiurl: '/api/v1/metric/default_list'\ntitle: \"Get Default Builtin Metric List\"\ntype: 'GET'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* Metric Suggestion for create strategy\n* base on `./data/metric` file\n\n### Response\n\n```Status: 200```\n```[\n  \"cpu.busy\",\n  \"cpu.cnt\",\n  \"cpu.guest\",\n  \"cpu.idle\",\n  \"cpu.iowait\",\n  \"cpu.irq\",\n  \"cpu.nice\",\n  \"cpu.softirq\",\n  \"cpu.steal\",\n  \"cpu.system\",\n  \"cpu.user\",\n  \"df.bytes.free\",\n  \"df.bytes.free.percent\"\n  ....\n]```\n"
  },
  {
    "path": "docs/_posts/Strategy/2017-01-01-strategy_create.md",
    "content": "---\ncategory: Strategy\napiurl: '/api/v1/strategy'\ntitle: \"Create Strategy\"\ntype: 'POST'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n\n### Request\n```{\n  \"tpl_id\": 221,\n  \"tags\": \"\",\n  \"run_end\": \"24:00\",\n  \"run_begin\": \"00:00\",\n  \"right_value\": \"1\",\n  \"priority\": 1,\n  \"op\": \"==\",\n  \"note\": \"this is a test\",\n  \"metric\": \"agent.alive\",\n  \"max_step\": 3,\n  \"func\": \"all(#3)\"\n}```\n\n### Response\n\n```Status: 200```\n```\n{\n  \"id\": 2,\n  \"tpl_id\": 221,\n  \"tags\": \"\",\n  \"run_end\": \"24:00\",\n  \"run_begin\": \"00:00\",\n  \"right_value\": \"1\",\n  \"priority\": 1,\n  \"op\": \"==\",\n  \"note\": \"this is a test\",\n  \"metric\": \"agent.alive\",\n  \"max_step\": 3,\n  \"func\": \"all(#3)\"\n}\n```\n"
  },
  {
    "path": "docs/_posts/Strategy/2017-01-01-strategy_delete.md",
    "content": "---\ncategory: Strategy\napiurl: '/api/v1/strategy/#{strategy_id}'\ntitle: \"Delete Strategy\"\ntype: 'DELETE'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/strategy/904\n\n### Response\n\n```Status: 200```\n```{\"message\":\"strategy:904 has been deleted\"}```\n"
  },
  {
    "path": "docs/_posts/Strategy/2017-01-01-strategy_info_by_id.md",
    "content": "---\ncategory: Strategy\napiurl: '/api/v1/strategy/#{strategy_id}'\ntitle: \"Get Strategy info by id\"\ntype: 'GET'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/strategy/904\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 904,\n  \"metric\": \"agent.alive\",\n  \"tags\": \"\",\n  \"max_step\": 3,\n  \"priority\": 1,\n  \"func\": \"all(#3)\",\n  \"op\": \"==\",\n  \"right_value\": \"1\",\n  \"note\": \"this is a test\",\n  \"run_begin\": \"00:00\",\n  \"run_end\": \"24:00\",\n  \"tpl_id\": 221\n}```\n"
  },
  {
    "path": "docs/_posts/Strategy/2017-01-01-strategy_list.md",
    "content": "---\ncategory: Strategy\napiurl: '/api/v1/strategy'\ntitle: \"Get Strategy List\"\ntype: 'GET'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 893,\n    \"metric\": \"process.num\",\n    \"tags\": \"name=redis\",\n    \"max_step\": 3,\n    \"priority\": 2,\n    \"func\": \"all(#2)\",\n    \"op\": \"<\",\n    \"right_value\": \"1\",\n    \"note\": \"Redis异常\",\n    \"run_begin\": \"\",\n    \"run_end\": \"\",\n    \"tpl_id\": 221\n  },\n  {\n    \"id\": 894,\n    \"metric\": \"process.num\",\n    \"tags\": \"name=smtp\",\n    \"max_step\": 3,\n    \"priority\": 2,\n    \"func\": \"all(#3)\",\n    \"op\": \"<\",\n    \"right_value\": \"1\",\n    \"note\": \"Smtp异常\",\n    \"run_begin\": \"\",\n    \"run_end\": \"\",\n    \"tpl_id\": 221\n  },\n  {\n    \"id\": 895,\n    \"metric\": \"process.num\",\n    \"tags\": \"cmdline=logger\",\n    \"max_step\": 3,\n    \"priority\": 3,\n    \"func\": \"all(#5)\",\n    \"op\": \"<\",\n    \"right_value\": \"2\",\n    \"note\": \"logger异常\",\n    \"run_begin\": \"\",\n    \"run_end\": \"\",\n    \"tpl_id\": 221\n  },\n]```\n"
  },
  {
    "path": "docs/_posts/Strategy/2017-01-01-strategy_update.md",
    "content": "---\ncategory: Strategy\napiurl: '/api/v1/strategy'\ntitle: \"Update Strategy\"\ntype: 'PUT'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n\n### Request\n```{\n  \"tags\": \"\",\n  \"run_end\": \"\",\n  \"run_begin\": \"\",\n  \"right_value\": \"1\",\n  \"priority\": 2,\n  \"op\": \"==\",\n  \"note\": \"this is a test\",\n  \"metric\": \"agent.alive\",\n  \"max_step\": 3,\n  \"id\": 904,\n  \"func\": \"all(#3)\"\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"stragtegy:904 has been updated\"}```\n"
  },
  {
    "path": "docs/_posts/Team/2017-01-01-team_create.md",
    "content": "---\ncategory: Team\napiurl: '/api/v1/team'\ntitle: \"Team Create\"\ntype: 'POST'\nsample_doc: 'team.html'\nlayout: default\n---\n\n新增使用者群組\n* [Session](#/authentication) Required\n* users: 属於该群组的user id list\n* resume: team的描述\n\n### Request\n```{\"team_name\": \"ateamname\",\"resume\": \"i'm descript\", \"users\": [1]}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"team created! Afftect row: 1, Affect refer: 1\"}```\n"
  },
  {
    "path": "docs/_posts/Team/2017-01-01-team_delete_by_id.md",
    "content": "---\ncategory: Team\napiurl: '/api/v1/team/#{team_id}'\ntitle: \"Delete Team By Id\"\ntype: 'DELETE'\nsample_doc: 'team.html'\nlayout: default\n---\n\n新增使用者群組\n* [Session](#/authentication) Required\n* ex. /api/v1/team/107\n* 除Admin外, 使用者只能更新自己创建的team\n\n### Response\n\n```Status: 200```\n```{\"message\":\"team 107 is deleted. Affect row: 1 / refer delete: 4\"}```\n"
  },
  {
    "path": "docs/_posts/Team/2017-01-01-team_info_by_id.md",
    "content": "---\ncategory: Team\napiurl: '/api/v1/team/t/#{team_id}'\ntitle: \"Get Team Info By Id\"\ntype: 'GET'\nsample_doc: 'team.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/team/t/107\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 107,\n  \"name\": \"ateamname\",\n  \"resume\": \"i'm descript\",\n  \"creator\": 1,\n  \"users\": [\n    {\n      \"id\": 4,\n      \"name\": \"test1\",\n      \"cnname\": \"翱鶚Test\",\n      \"email\": \"root123@cepave.com\",\n      \"phone\": \"99999999999\",\n      \"im\": \"44955834958\",\n      \"qq\": \"904394234239\",\n      \"role\": 0\n    },\n    {\n      \"id\": 7,\n      \"name\": \"cepave1\",\n      \"cnname\": \"\",\n      \"email\": \"\",\n      \"phone\": \"\",\n      \"im\": \"\",\n      \"qq\": \"904394234239\",\n      \"role\": 0\n    }\n  ]\n}```\n"
  },
  {
    "path": "docs/_posts/Team/2017-01-01-team_info_by_name.md",
    "content": "---\ncategory: Team\napiurl: '/api/v1/team/name/#{team_name}'\ntitle: \"Get Team Info by name\"\ntype: 'GET'\nsample_doc: 'team.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/team/name/plus-dev\n\n### Response\n\n```Status: 200```\n```\n{\n    \"creator\": 6,\n    \"creator_name\": \"\",\n    \"id\": 10,\n    \"name\": \"plus-dev\",\n    \"resume\": \"test intro\",\n    \"users\": [\n        {\n            \"cnname\": \"laiwei\",\n            \"email\": \"laiwei@xxx.com\",\n            \"id\": 1,\n            \"im\": \"yyyyx\",\n            \"name\": \"laiwei1\",\n            \"phone\": \"15011518472\",\n            \"qq\": \"3805112124444455\",\n            \"role\": 2\n        }\n    ]\n}```\n"
  },
  {
    "path": "docs/_posts/Team/2017-01-01-team_list.md",
    "content": "---\ncategory: Team\napiurl: '/api/v1/team'\ntitle: \"Team List\"\ntype: 'GET'\nsample_doc: 'team.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* q: 使用 regex 查询字符, 查询team name\n  * option 参数\n\n### Request\n```q=a.+```\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 1,\n    \"name\": \"a\",\n    \"resume\": \"\",\n    \"creator\": 1\n  },\n  {\n    \"id\": 5,\n    \"name\": \"atestteam\",\n    \"resume\": \"i'm test\",\n    \"creator\": 16\n  },\n  {\n    \"id\": 107,\n    \"name\": \"ateamname\",\n    \"resume\": \"i'm descript\",\n    \"creator\": 1\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/Team/2017-01-01-team_update.md",
    "content": "---\ncategory: Team\napiurl: '/api/v1/team'\ntitle: \"Team Update\"\ntype: 'PUT'\nsample_doc: 'team.html'\nlayout: default\n---\n\n更新使用者群組\n* [Session](#/authentication) Required\n* users: 属於该群组的user id list\n* resume: team的描述\n* name: team的名字\n* 除Admin外, 使用者只能更新自己创建的team\n\n### Request\n```{\n  \"team_id\": 107,\n  \"name\": \"new_name\",\n  \"resume\": \"i'm descript update\",\n  \"users\": [4,5,6,7]\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"team updated!\"}```\n"
  },
  {
    "path": "docs/_posts/Team/2018-11-19-add-user-to-team.md",
    "content": "---\ncategory: Team\napiurl: '/api/v1/team/user'\ntitle: \"Add users to team\"\ntype: 'POST'\nsample_doc: ''\nlayout: default\n---\n\n添加用户到某个组\n* [Session](#/authentication) Required\n* users: 待添加到 team 中的用户名列表\n* team_id: 目标 team 的 team_id\n\n### Request\n```{\n  \"team_id\": 107,\n  \"users\": [\"root\", \"test1\"]\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"add successful\"}```\n"
  },
  {
    "path": "docs/_posts/Template/2017-01-01-tpl_action_create.md",
    "content": "---\ncategory: Template\napiurl: '/api/v1/template/action'\ntitle: \"Create Template Action\"\ntype: 'POST'\nsample_doc: 'template.html'\nlayout: default\n---\n\nCreate Action to a Template\n* [Session](#/authentication) Required\n* params:\n  * url: callback url\n  * uic: 需要通知的使用者群组(name)\n  * callback: enable/disable\n\n### Request\n```{\n  \"url\": \"\",\n  \"uic\": \"test,tt2\",\n  \"tpl_id\": 225,\n  \"callback\": 1,\n  \"before_callback_sms\": 0,\n  \"before_callback_mail\": 0,\n  \"after_callback_sms\": 0,\n  \"after_callback_mail\": 0\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"template created\"}```\n"
  },
  {
    "path": "docs/_posts/Template/2017-01-01-tpl_action_update.md",
    "content": "---\ncategory: Template\napiurl: '/api/v1/template/action'\ntitle: \"Update Template Action\"\ntype: 'PUT'\nsample_doc: 'template.html'\nlayout: default\n---\n\nUpdate Action\n* [Session](#/authentication) Required\n* params:\n  * url: callback url\n  * uic: 需要通知的使用者群组(name)\n  * callback: enable/disable\n\n### Request\n```{\n  \"url\": \"\",\n  \"uic\": \"test,tt2,tt3\",\n  \"id\": 175,\n  \"callback\": 1,\n  \"before_callback_sms\": 0,\n  \"before_callback_mail\": 0,\n  \"after_callback_sms\": 0,\n  \"after_callback_mail\": 0\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"action is updated, row affected: 1\"}```\n"
  },
  {
    "path": "docs/_posts/Template/2017-01-01-tpl_create.md",
    "content": "---\ncategory: Template\napiurl: '/api/v1/template'\ntitle: \"Create Template\"\ntype: 'POST'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* parent_id: 继承现有Template\n\n### Request\n```{\"parent_id\":0,\"name\":\"AtmpForTesting\"}```\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 2,\n  \"parent_id\": 0,\n  \"tpl_name\": \"AtmpForTesting\",\n  \"action_id\": 0,\n  \"create_user\": \"root\"\n}```\n"
  },
  {
    "path": "docs/_posts/Template/2017-01-01-tpl_delete.md",
    "content": "---\ncategory: Template\napiurl: '/api/v1/template/#{template_id}'\ntitle: \"Delete Template\"\ntype: 'DELETE'\nsample_doc: 'template.html'\nlayout: default\n---\n\nDelete a Template\n* [Session](#/authentication) Required\n* ex. /api/v1/template/225\n\n### Response\n\n```Status: 200```\n```{\"message\":\"template 225 has been deleted\"}```\n"
  },
  {
    "path": "docs/_posts/Template/2017-01-01-tpl_hgp_list.md",
    "content": "---\ncategory: Template\napiurl: '/api/v1/template/#{template_id}/hostgroup'\ntitle: \"Get hostgroups list by id\"\ntype: 'GET'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/template/178/hostgroup\n\n### Response\n\n```Status: 200```\n```{\n  \"hostgroups\": [{\n      \"id\":33,\n      \"grp_name\":\"HostGroup\",\n      \"create_user\":\"root\"\n    }\n  ],\n  \"template\": {\n    \"id\": 178,\n    \"tpl_name\": \"TemplateA\",\n    \"parent_id\": 0,\n    \"action_id\": 141,\n    \"create_user\": \"root\"\n  }\n}```\n"
  },
  {
    "path": "docs/_posts/Template/2017-01-01-tpl_info_by_id.md",
    "content": "---\ncategory: Template\napiurl: '/api/v1/template/#{template_id}'\ntitle: \"Get Template Info by id\"\ntype: 'GET'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/template/178\n\n### Response\n\n```Status: 200```\n```{\n  \"action\": {\n    \"id\": 141,\n    \"uic\": \"admin,mm1\",\n    \"url\": \"\",\n    \"callback\": 0,\n    \"before_callback_sms\": 0,\n    \"before_callback_mail\": 0,\n    \"after_callback_sms\": 0,\n    \"after_callback_mail\": 0\n  },\n  \"stratges\": [\n    {\n      \"id\": 686,\n      \"metric\": \"xxx.check\",\n      \"tags\": \"name=xxx\",\n      \"max_step\": 3,\n      \"priority\": 2,\n      \"func\": \"all(#2)\",\n      \"op\": \"<\",\n      \"right_value\": \"1\",\n      \"note\": \"xxx服务异常\",\n      \"run_begin\": \"\",\n      \"run_end\": \"\",\n      \"tpl_id\": 178\n    },\n    {\n      \"id\": 687,\n      \"metric\": \"xxx.sync\",\n      \"tags\": \"\",\n      \"max_step\": 3,\n      \"priority\": 2,\n      \"func\": \"all(#3)\",\n      \"op\": \"!=\",\n      \"right_value\": \"0\",\n      \"note\": \"XXX同步异常\",\n      \"run_begin\": \"\",\n      \"run_end\": \"\",\n      \"tpl_id\": 178\n    },\n    {\n      \"id\": 688,\n      \"metric\": \"bbb.check.mq\",\n      \"tags\": \"\",\n      \"max_step\": 3,\n      \"priority\": 2,\n      \"func\": \"all(#3)\",\n      \"op\": \"==\",\n      \"right_value\": \"1\",\n      \"note\": \"bbb连接MQ异常\",\n      \"run_begin\": \"\",\n      \"run_end\": \"\",\n      \"tpl_id\": 178\n    },\n    {\n      \"id\": 793,\n      \"metric\": \"aaa.proc.num\",\n      \"tags\": \"\",\n      \"max_step\": 3,\n      \"priority\": 2,\n      \"func\": \"all(#3)\",\n      \"op\": \"==\",\n      \"right_value\": \"1\",\n      \"note\": \"aaaa 进程大于5\",\n      \"run_begin\": \"\",\n      \"run_end\": \"\",\n      \"tpl_id\": 178\n    }\n  ],\n  \"template\": {\n    \"id\": 178,\n    \"tpl_name\": \"TemplateA\",\n    \"parent_id\": 0,\n    \"action_id\": 141,\n    \"create_user\": \"root\"\n  }\n}```\n"
  },
  {
    "path": "docs/_posts/Template/2017-01-01-tpl_list.md",
    "content": "---\ncategory: Template\napiurl: '/api/v1/template'\ntitle: \"Template List\"\ntype: 'GET'\nsample_doc: 'template.html'\nlayout: default\n---\n\nTemplate List\n* [Session](#/authentication) Required\n\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 1,\n    \"tpl_name\": \"cpu.board\",\n    \"parent_id\": 0,\n    \"action_id\": 5,\n    \"create_user\": \"usera\"\n  },\n  {\n    \"id\": 2,\n    \"tpl_name\": \"traffic checking\",\n    \"parent_id\": 0,\n    \"action_id\": 6,\n    \"create_user\": \"userb\"\n  },\n  {\n    \"id\": 3,\n    \"tpl_name\": \"cputest\",\n    \"parent_id\": 0,\n    \"action_id\": 7,\n    \"create_user\": \"userc\"\n  },\n  {\n    \"id\": 5,\n    \"tpl_name\": \"all metrics base\",\n    \"parent_id\": 0,\n    \"action_id\": 12,\n    \"create_user\": \"root\"\n  }\n]```\n"
  },
  {
    "path": "docs/_posts/Template/2017-01-01-tpl_update.md",
    "content": "---\ncategory: Template\napiurl: '/api/v1/template/'\ntitle: \"Update Template\"\ntype: 'PUT'\nsample_doc: 'template.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* parent_id: 继承现有Template\n\n### Request\n```{\n  \"tpl_id\": 225,\n  \"parent_id\": 0,\n  \"name\": \"AtmpForTesting2\"\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"template updated\"}```\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_change_password.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/cgpasswd'\ntitle: 'Change Password'\ntype: 'PUT'\nsample_doc: 'user.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n```{\n  \"new_password\": \"test1\",\n  \"old_password\": \"test1\"\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"password updated!\"}```\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_create.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/create'\ntitle: 'Create User'\ntype: 'POST'\nsample_doc: 'user.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Request\n```{\"name\": \"test\",\"password\": \"test\", \"email\":\"xxx@xxx.com\", \"cnname\": \"翱鹗\"}```\n\n### Response\n\n```Status: 200```\n```{\n  \"name\": \"owltester\",\n  \"password\": \"mypassword\",\n  \"cnname\": \"翱鹗\",\n  \"email\": \"root123@cepave.com\",\n  \"im\": \"44955834958\",\n  \"phone\": \"99999999999\",\n  \"qq\": \"904394234239\"\n}```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_current.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/current'\ntitle: 'Current User info'\ntype: 'GET'\nsample_doc: 'user.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* 当前使用者资讯\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 2,\n  \"name\": \"root\",\n  \"cnname\": \"\",\n  \"email\": \"\",\n  \"phone\": \"\",\n  \"im\": \"\",\n  \"qq\": \"\",\n  \"role\": 2\n}```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_get_info_by_id.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/u/#{user_id}'\ntitle: 'Get User info by id'\ntype: 'GET'\nsample_doc: 'user.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* `Admin` usage\n* ex. /api/v1/user/u/4\n\n### Response\n\n```Status: 200```\n```{\n  \"id\": 4,\n  \"name\": \"userA\",\n  \"cnname\": \"tear\",\n  \"email\": \"\",\n  \"phone\": \"\",\n  \"im\": \"\",\n  \"qq\": \"\",\n  \"role\": 0\n}```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_get_info_by_name.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/name/#{user_name}'\ntitle: 'Get User info by name'\ntype: 'GET'\nsample_doc: 'user.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* `Admin` usage\n* ex. /api/v1/user/name/laiwei\n\n### Response\n\n```Status: 200```\n```\n{\n    \"cnname\": \"laiwei8\",\n    \"email\": \"laiwei8@xx\",\n    \"id\": 8,\n    \"im\": \"\",\n    \"name\": \"laiwei8\",\n    \"phone\": \"\",\n    \"qq\": \"\",\n    \"role\": 0\n}```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_get_teams.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/u/:uid/teams'\ntitle: 'Get user teams'\ntype: 'GET'\nsample_doc: 'user.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/user/u/4/teams\n\n### Response\n\n```Status: 200```\n```{\"teams\":\n  [{\n    \"id\":3,\n    \"name\":\"root\",\n    \"resume\":\"\",\n    \"creator\":5},\n   {\"id\":32,\n    \"name\":\"testteam\",\n    \"resume\":\"test22\",\n    \"creator\":5\n   }]\n} ```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_is_in_teams.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/u/:uid/in_teams'\ntitle: 'Check user in teams or not'\ntype: 'GET'\nsample_doc: 'user.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n* ex. /api/v1/user/u/4/in_teams?team_names=team1,team4\n\n### Request\nContent-type: application/x-www-form-urlencoded\n```team_names=team1,team2```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"true\"} ```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_list.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/users'\ntitle: 'User List'\ntype: 'GET'\nsample_doc: 'user.html'\nlayout: default\n---\n\n* [Session](#/authentication) Required\n\n### Response\n\n```Status: 200```\n```[\n  {\n    \"id\": 1,\n    \"name\": \"root\",\n    \"cnname\": \"\",\n    \"email\": \"\",\n    \"phone\": \"\",\n    \"im\": \"\",\n    \"qq\": \"904394234239\",\n    \"role\": 2\n  },\n  {\n    \"id\": 32,\n    \"name\": \"owltester\",\n    \"cnname\": \"翱鶚\",\n    \"email\": \"root123@cepave.com\",\n    \"phone\": \"99999999999\",\n    \"im\": \"44955834958\",\n    \"qq\": \"904394234239\",\n    \"role\": 0\n  }\n]```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_login.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/login'\ntitle: 'Login'\ntype: 'POST'\nsample_doc: 'user.html'\nlayout: default\n---\n\n使用者登入\n\n### Request\n```{\n  \"name\": \"test2\",\n  \"password\": \"test2\"\n}```\n\n### Response\n\n```Status: 200```\n```{\n  \"sig\": \"9d791331c0ea11e690c5001500c6ca5a\",\n  \"name\": \"test2\",\n  \"admin\": false\n}```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_logout.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/logout'\ntitle: 'Logout'\ntype: 'GET'\nsample_doc: 'user.html'\nlayout: default\n---\n\n使用者登出\n* [Session](#/authentication) Required\n\n### Response\n\nSends back a collection of things.\n\n```Status: 200```\n```{\"message\":\"logout successful\"}```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2017-01-01-user_update.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/update'\ntitle: 'Update User'\ntype: 'PUT'\nsample_doc: 'user.html'\nlayout: default\n---\n\n更新使用者\n* [Session](#/authentication) Required\n\n### Request\n```{\n  \"cnname\": \"翱鶚Test\",\n  \"email\": \"root123@cepave.com\",\n  \"im\": \"44955834958\",\n  \"phone\": \"99999999999\",\n  \"qq\": \"904394234239\"\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"user info updated\"}```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/_posts/User/2019-04-14-update-specific-user.md",
    "content": "---\ncategory: User\napiurl: '/api/v1/user/u/:uid'\ntitle: 'Update Specific User'\ntype: 'PUT'\nsample_doc: 'user.html'\nlayout: default\n---\n\n更新使用者\n* [Session](#/authentication) Required\n\n### Request\n```{\n  \"cnname\": \"翱鶚Test\",\n  \"email\": \"root123@cepave.com\",\n  \"im\": \"44955834958\",\n  \"phone\": \"99999999999\",\n  \"qq\": \"904394234239\"\n}```\n\n### Response\n\n```Status: 200```\n```{\"message\":\"user info updated\"}```\n\nFor more example, see the [user](/doc/user.html).\n\nFor errors responses, see the [response status codes documentation](#/response-status-codes).\n"
  },
  {
    "path": "docs/assets.css",
    "content": "/*! normalize.css v2.1.0 | MIT License | git.io/normalize */\n\n/* ==========================================================================\n   HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Correct `block` display not defined in IE 8/9.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nnav,\nsection,\nsummary {\n    display: block;\n}\n\n/**\n * Correct `inline-block` display not defined in IE 8/9.\n */\n\naudio,\ncanvas,\nvideo {\n    display: inline-block;\n}\n\n/**\n * Prevent modern browsers from displaying `audio` without controls.\n * Remove excess height in iOS 5 devices.\n */\n\naudio:not([controls]) {\n    display: none;\n    height: 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\n[hidden] {\n    display: none;\n}\n\n/* ==========================================================================\n   Base\n   ========================================================================== */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Prevent iOS text size adjust after orientation change, without disabling\n *    user zoom.\n */\n\nhtml {\n    font-family: sans-serif; /* 1 */\n    -webkit-text-size-adjust: 100%; /* 2 */\n    -ms-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove default margin.\n */\n\nbody {\n    margin: 0;\n}\n\n/* ==========================================================================\n   Links\n   ========================================================================== */\n\n/**\n * Address `outline` inconsistency between Chrome and other browsers.\n */\n\na:focus {\n    outline: thin dotted;\n}\n\n/**\n * Improve readability when focused and also mouse hovered in all browsers.\n */\n\na:active,\na:hover {\n    outline: 0;\n}\n\n/* ==========================================================================\n   Typography\n   ========================================================================== */\n\n/**\n * Address variable `h1` font-size and margin within `section` and `article`\n * contexts in Firefox 4+, Safari 5, and Chrome.\n */\n\nh1 {\n    font-size: 2em;\n    margin: 0.67em 0;\n}\n\n/**\n * Address styling not present in IE 8/9, Safari 5, and Chrome.\n */\n\nabbr[title] {\n    border-bottom: 1px dotted;\n}\n\n/**\n * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.\n */\n\nb,\nstrong {\n    font-weight: bold;\n}\n\n/**\n * Address styling not present in Safari 5 and Chrome.\n */\n\ndfn {\n    font-style: italic;\n}\n\n/**\n * Address differences between Firefox and other browsers.\n */\n\nhr {\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    height: 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\nmark {\n    background: #ff0;\n    color: #000;\n}\n\n/**\n * Correct font family set oddly in Safari 5 and Chrome.\n */\n\ncode,\nkbd,\npre,\nsamp {\n    font-family: monospace, serif;\n    font-size: 1em;\n}\n\n/**\n * Improve readability of pre-formatted text in all browsers.\n */\n\npre {\n    white-space: pre-wrap;\n}\n\n/**\n * Set consistent quote types.\n */\n\nq {\n    quotes: \"\\201C\" \"\\201D\" \"\\2018\" \"\\2019\";\n}\n\n/**\n * Address inconsistent and variable font size in all browsers.\n */\n\nsmall {\n    font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\n */\n\nsub,\nsup {\n    font-size: 75%;\n    line-height: 0;\n    position: relative;\n    vertical-align: baseline;\n}\n\nsup {\n    top: -0.5em;\n}\n\nsub {\n    bottom: -0.25em;\n}\n\n/* ==========================================================================\n   Embedded content\n   ========================================================================== */\n\n/**\n * Remove border when inside `a` element in IE 8/9.\n */\n\nimg {\n    border: 0;\n}\n\n/**\n * Correct overflow displayed oddly in IE 9.\n */\n\nsvg:not(:root) {\n    overflow: hidden;\n}\n\n/* ==========================================================================\n   Figures\n   ========================================================================== */\n\n/**\n * Address margin not present in IE 8/9 and Safari 5.\n */\n\nfigure {\n    margin: 0;\n}\n\n/* ==========================================================================\n   Forms\n   ========================================================================== */\n\n/**\n * Define consistent border, margin, and padding.\n */\n\nfieldset {\n    border: 1px solid #c0c0c0;\n    margin: 0 2px;\n    padding: 0.35em 0.625em 0.75em;\n}\n\n/**\n * 1. Correct `color` not being inherited in IE 8/9.\n * 2. Remove padding so people aren't caught out if they zero out fieldsets.\n */\n\nlegend {\n    border: 0; /* 1 */\n    padding: 0; /* 2 */\n}\n\n/**\n * 1. Correct font family not being inherited in all browsers.\n * 2. Correct font size not being inherited in all browsers.\n * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.\n */\n\nbutton,\ninput,\nselect,\ntextarea {\n    font-family: inherit; /* 1 */\n    font-size: 100%; /* 2 */\n    margin: 0; /* 3 */\n}\n\n/**\n * Address Firefox 4+ setting `line-height` on `input` using `!important` in\n * the UA stylesheet.\n */\n\nbutton,\ninput {\n    line-height: normal;\n}\n\n/**\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\n * All other form control elements do not inherit `text-transform` values.\n * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.\n * Correct `select` style inheritance in Firefox 4+ and Opera.\n */\n\nbutton,\nselect {\n    text-transform: none;\n}\n\n/**\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n *    and `video` controls.\n * 2. Correct inability to style clickable `input` types in iOS.\n * 3. Improve usability and consistency of cursor style between image-type\n *    `input` and others.\n */\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n    -webkit-appearance: button; /* 2 */\n    cursor: pointer; /* 3 */\n}\n\n/**\n * Re-set default cursor for disabled elements.\n */\n\nbutton[disabled],\nhtml input[disabled] {\n    cursor: default;\n}\n\n/**\n * 1. Address box sizing set to `content-box` in IE 8/9.\n * 2. Remove excess padding in IE 8/9.\n */\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n    box-sizing: border-box; /* 1 */\n    padding: 0; /* 2 */\n}\n\n/**\n * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.\n * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome\n *    (include `-moz` to future-proof).\n */\n\ninput[type=\"search\"] {\n    -webkit-appearance: textfield; /* 1 */\n    -moz-box-sizing: content-box;\n    -webkit-box-sizing: content-box; /* 2 */\n    box-sizing: content-box;\n}\n\n/**\n * Remove inner padding and search cancel button in Safari 5 and Chrome\n * on OS X.\n */\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n    -webkit-appearance: none;\n}\n\n/**\n * Remove inner padding and border in Firefox 4+.\n */\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n    border: 0;\n    padding: 0;\n}\n\n/**\n * 1. Remove default vertical scrollbar in IE 8/9.\n * 2. Improve readability and alignment in all browsers.\n */\n\ntextarea {\n    overflow: auto; /* 1 */\n    vertical-align: top; /* 2 */\n}\n\n/* ==========================================================================\n   Tables\n   ========================================================================== */\n\n/**\n * Remove most spacing between table cells.\n */\n\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}\n\n\n\n/* GENERAL */\nhtml,\nbody {\n  height: 100%;\n}\n\nbody {\n  background: #fff;\n}\n\nbody,\ninput,\ntextarea {\n  color: #191919;\n  font: 12px/120% 'Open Sans', Arial, sans-serif;\n}\n\na {\n  color: #119bdf;\n  text-decoration: none;\n}\na:hover {\n  color: #29aeef;\n  text-decoration: underline;\n}\n\nh1,\nh2,\nh3,\nh4,\np,\nul,\ncode {\n  margin: 0 0 20px;\n}\n\ncode {\n  font-family: 'Monaco', monospace, sans-serif;\n}\n\n/* SIDEBAR */\n#sidebar {\n  background: #191919;\n  color: #fff;\n  float: left;  \n  overflow: auto;\n  max-width: 400px;\n  /*margin-top: 54px;*/\n  height: 100%;\n}\n\n#sidebar h1 {\n  background: #111;\n  font-size: 14px;\n  margin: 0;\n  padding: 20px;\n  text-transform: uppercase;\n}\n\n#sidebar h2 {\n  color: #888;\n  font-size: 12px;\n  margin: 0;\n}\n\n#sidebar ul {\n  list-style: none;\n  margin: 0;\n  padding: 0;\n}\n\n#sidebar ul#links {\n  padding: 20px;\n}\n\n#sidebar ul ul {\n  padding-left: 20px;\n}\n\n#sidebar ul li a {\n  color: #fff;\n  display: block;\n  padding: 0 0 15px;\n}\n#sidebar ul li a:active,\n#sidebar ul li a.active {\n  text-decoration: underline;\n}\n\n#sidebar input {\n  background: #111;\n  border: 0;\n  border-radius: 2px;\n  -moz-border-radius: 2px;\n  -webkit-border-radius: 2px;\n  box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);\n  -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.2);\n  -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.2);\n  color: #ddd;\n  margin-bottom: 20px;\n  padding: 5px 10px;\n}\n#sidebar input:active,\n#sidebar input:focus {\n  border-color: #ccc;\n  box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.1);\n  -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1);\n  -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1);\n  outline: none;\n}\n\n/* References */\n#content {\n  float:left;\n  padding: 20px;\n  max-width: 700px;\n  overflow: auto;\n  height: 100%;\n}\n\n#content .control {\n  cursor: pointer;\n  font-size: 12px;\n  margin-left: 15px;\n}\n\n#content article {\n  clear: both;\n  margin: 15px 0;\n}\n\n#content article > a {\n  background: #333;\n  border-radius: 2px;\n  -moz-border-radius: 2px;\n  -webkit-border-radius: 2px;\n  cursor: pointer;\n  display: block;\n  padding: 15px;\n}\n#content article > a:hover {\n  background: #222;\n  text-decoration: none;\n}\n\n#content a h2 {\n  color: #fff;\n  font-size: 14px;\n  font-weight: normal;\n  margin: 0;\n}\n\n#content a h2 code {\n  float: right;\n  font-size: 12px;\n}\n\n#content a h2 code b {\n  border-radius: 2px;\n  -moz-border-radius: 2px;\n  -webkit-border-radius: 2px;\n  color: #fff;\n  font-weight: normal;\n  padding: 3px 6px;\n}\n\n/* Default */\n#content article {\n  border-color: #e2e7ea;\n}\n\n#content article a h2 code {\n  color: #657e8b;\n}\n\n#content article a h2 code b {\n  background: #657e8b;\n  text-transform: uppercase;\n}\n\n/* GET */\n#content article.GET a h2 code {\n  color: #119bdf;\n}\n\n#content article.GET a h2 code b {\n  background: #119bdf;\n}\n\n/* POST */\n#content article.POST a h2 code {\n  color: #52ce0e;\n}\n\n#content article.POST a h2 code b {\n  background: #52ce0e;\n}\n\n/* PUT */\n#content article.PUT a h2 code {\n  color: #e08f10;\n}\n\n#content article.PUT a h2 code b {\n  background: #e08f10;\n}\n\n/* DELETE */\n#content article.DELETE a h2 code {\n  color: #e02a10;\n}\n\n#content article.DELETE a h2 code b {\n  background: #e02a10;\n}\n\n/* Reference's body */\n#content h3 {\n}\n\n#content .body {\n  border-top: 1px solid #eef1f2;\n  display: block;\n  padding: 15px 15px 0;\n}\n\n#content .body code {\n  border: 1px solid #e2e7ea;\n  background: #eef1f2;\n  border-radius: 2px;\n  -moz-border-radius: 2px;\n  -webkit-border-radius: 2px;\n  color: #546974;\n  padding: 0 1px;\n}\n\n#content .body p > code {\n  display: block;\n  padding: 15px;\n  white-space: pre;\n}\n\ntable{\n    border-collapse: collapse;\n    border-spacing: 1;\n    border:2px solid #ff0000;\n}\n\nth{\n    border:2px solid #000000;\n}\n\ntd{\n    border:1px solid #000000;\n}\n"
  },
  {
    "path": "docs/assets.js",
    "content": "\n/**\n * hasOwnProperty.\n */\n\nvar has = Object.prototype.hasOwnProperty;\n\n/**\n * Require the given path.\n *\n * @param {String} path\n * @return {Object} exports\n * @api public\n */\n\nfunction require(path, parent, orig) {\n  var resolved = require.resolve(path);\n\n  // lookup failed\n  if (null == resolved) {\n    orig = orig || path;\n    parent = parent || 'root';\n    var err = new Error('Failed to require \"' + orig + '\" from \"' + parent + '\"');\n    err.path = orig;\n    err.parent = parent;\n    err.require = true;\n    throw err;\n  }\n\n  var module = require.modules[resolved];\n\n  // perform real require()\n  // by invoking the module's\n  // registered function\n  if (!module.exports) {\n    module.exports = {};\n    module.client = module.component = true;\n    module.call(this, module.exports, require.relative(resolved), module);\n  }\n\n  return module.exports;\n}\n\n/**\n * Registered modules.\n */\n\nrequire.modules = {};\n\n/**\n * Registered aliases.\n */\n\nrequire.aliases = {};\n\n/**\n * Resolve `path`.\n *\n * Lookup:\n *\n *   - PATH/index.js\n *   - PATH.js\n *   - PATH\n *\n * @param {String} path\n * @return {String} path or null\n * @api private\n */\n\nrequire.resolve = function(path) {\n  var index = path + '/index.js';\n\n  var paths = [\n    path,\n    path + '.js',\n    path + '.json',\n    path + '/index.js',\n    path + '/index.json'\n  ];\n\n  for (var i = 0; i < paths.length; i++) {\n    var path = paths[i];\n    if (has.call(require.modules, path)) return path;\n  }\n\n  if (has.call(require.aliases, index)) {\n    return require.aliases[index];\n  }\n};\n\n/**\n * Normalize `path` relative to the current path.\n *\n * @param {String} curr\n * @param {String} path\n * @return {String}\n * @api private\n */\n\nrequire.normalize = function(curr, path) {\n  var segs = [];\n\n  if ('.' != path.charAt(0)) return path;\n\n  curr = curr.split('/');\n  path = path.split('/');\n\n  for (var i = 0; i < path.length; ++i) {\n    if ('..' == path[i]) {\n      curr.pop();\n    } else if ('.' != path[i] && '' != path[i]) {\n      segs.push(path[i]);\n    }\n  }\n\n  return curr.concat(segs).join('/');\n};\n\n/**\n * Register module at `path` with callback `definition`.\n *\n * @param {String} path\n * @param {Function} definition\n * @api private\n */\n\nrequire.register = function(path, definition) {\n  require.modules[path] = definition;\n};\n\n/**\n * Alias a module definition.\n *\n * @param {String} from\n * @param {String} to\n * @api private\n */\n\nrequire.alias = function(from, to) {\n  if (!has.call(require.modules, from)) {\n    throw new Error('Failed to alias \"' + from + '\", it does not exist');\n  }\n  require.aliases[to] = from;\n};\n\n/**\n * Return a require function relative to the `parent` path.\n *\n * @param {String} parent\n * @return {Function}\n * @api private\n */\n\nrequire.relative = function(parent) {\n  var p = require.normalize(parent, '..');\n\n  /**\n   * lastIndexOf helper.\n   */\n\n  function lastIndexOf(arr, obj) {\n    var i = arr.length;\n    while (i--) {\n      if (arr[i] === obj) return i;\n    }\n    return -1;\n  }\n\n  /**\n   * The relative require() itself.\n   */\n\n  function localRequire(path) {\n    var resolved = localRequire.resolve(path);\n    return require(resolved, parent, path);\n  }\n\n  /**\n   * Resolve relative to the parent.\n   */\n\n  localRequire.resolve = function(path) {\n    // resolve deps by returning\n    // the dep in the nearest \"deps\"\n    // directory\n    if ('.' != path.charAt(0)) {\n      var segs = parent.split('/');\n      var i = lastIndexOf(segs, 'deps') + 1;\n      if (!i) i = 0;\n      path = segs.slice(0, i + 1).join('/') + '/deps/' + path;\n      return path;\n    }\n    return require.normalize(p, path);\n  };\n\n  /**\n   * Check if module is defined at `path`.\n   */\n\n  localRequire.exists = function(path) {\n    return has.call(require.modules, localRequire.resolve(path));\n  };\n\n  return localRequire;\n};\n\nrequire.register(\"component-jquery/index.js\", function(exports, require, module){\n/*!\n * jQuery JavaScript Library v1.7.3pre\n * http://jquery.com/\n *\n * Copyright 2011, John Resig\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n * Copyright 2011, The Dojo Foundation\n * Released under the MIT, BSD, and GPL Licenses.\n *\n * Date: Thu May 3 11:06:50 2012 -0700\n */\n(function( window, undefined ) {\n\n// Use the correct document accordingly with window argument (sandbox)\nvar document = window.document,\n\tnavigator = window.navigator,\n\tlocation = window.location;\nvar jQuery = (function() {\n\n// Define a local copy of jQuery\nvar jQuery = function( selector, context ) {\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\treturn new jQuery.fn.init( selector, context, rootjQuery );\n\t},\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$,\n\n\t// A central reference to the root jQuery(document)\n\trootjQuery,\n\n\t// A simple way to check for HTML strings or ID strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\tquickExpr = /^(?:[^#<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]*)$)/,\n\n\t// Check if a string has a non-whitespace character in it\n\trnotwhite = /\\S/,\n\n\t// Used for trimming whitespace\n\ttrimLeft = /^\\s+/,\n\ttrimRight = /\\s+$/,\n\n\t// Match a standalone tag\n\trsingleTag = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,\n\n\t// JSON RegExp\n\trvalidchars = /^[\\],:{}\\s]*$/,\n\trvalidescape = /\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,\n\trvalidtokens = /\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,\n\trvalidbraces = /(?:^|:|,)(?:\\s*\\[)+/g,\n\n\t// Useragent RegExp\n\trwebkit = /(webkit)[ \\/]([\\w.]+)/,\n\tropera = /(opera)(?:.*version)?[ \\/]([\\w.]+)/,\n\trmsie = /(msie) ([\\w.]+)/,\n\trmozilla = /(mozilla)(?:.*? rv:([\\w.]+))?/,\n\n\t// Matches dashed string for camelizing\n\trdashAlpha = /-([a-z]|[0-9])/ig,\n\trmsPrefix = /^-ms-/,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn ( letter + \"\" ).toUpperCase();\n\t},\n\n\t// Keep a UserAgent string for use with jQuery.browser\n\tuserAgent = navigator.userAgent,\n\n\t// For matching the engine and version of the browser\n\tbrowserMatch,\n\n\t// The deferred used on DOM ready\n\treadyList,\n\n\t// The ready event handler\n\tDOMContentLoaded,\n\n\t// Save a reference to some core methods\n\ttoString = Object.prototype.toString,\n\thasOwn = Object.prototype.hasOwnProperty,\n\tpush = Array.prototype.push,\n\tslice = Array.prototype.slice,\n\ttrim = String.prototype.trim,\n\tindexOf = Array.prototype.indexOf,\n\n\t// [[Class]] -> type pairs\n\tclass2type = {};\n\njQuery.fn = jQuery.prototype = {\n\tconstructor: jQuery,\n\tinit: function( selector, context, rootjQuery ) {\n\t\tvar match, elem, ret, doc;\n\n\t\t// Handle $(\"\"), $(null), or $(undefined)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle $(DOMElement)\n\t\tif ( selector.nodeType ) {\n\t\t\tthis.context = this[0] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\t\t}\n\n\t\t// The body element only exists once, optimize finding it\n\t\tif ( selector === \"body\" && !context && document.body ) {\n\t\t\tthis.context = document;\n\t\t\tthis[0] = document.body;\n\t\t\tthis.selector = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\t// Are we dealing with HTML string or an ID?\n\t\t\tif ( selector.charAt(0) === \"<\" && selector.charAt( selector.length - 1 ) === \">\" && selector.length >= 3 ) {\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = quickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Verify a match, and that no context was specified for #id\n\t\t\tif ( match && (match[1] || !context) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[1] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[0] : context;\n\t\t\t\t\tdoc = ( context ? context.ownerDocument || context : document );\n\n\t\t\t\t\t// If a single string is passed in and it's a single tag\n\t\t\t\t\t// just do a createElement and skip the rest\n\t\t\t\t\tret = rsingleTag.exec( selector );\n\n\t\t\t\t\tif ( ret ) {\n\t\t\t\t\t\tif ( jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\t\tselector = [ document.createElement( ret[1] ) ];\n\t\t\t\t\t\t\tjQuery.fn.attr.call( selector, context, true );\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tselector = [ doc.createElement( ret[1] ) ];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tret = jQuery.buildFragment( [ match[1] ], [ doc ] );\n\t\t\t\t\t\tselector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.merge( this, selector );\n\n\t\t\t\t// HANDLE: $(\"#id\")\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[2] );\n\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE and Opera return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id !== match[2] ) {\n\t\t\t\t\t\t\treturn rootjQuery.find( selector );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Otherwise, we inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[0] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || rootjQuery ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn rootjQuery.ready( selector );\n\t\t}\n\n\t\tif ( selector.selector !== undefined ) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t},\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The current version of jQuery being used\n\tjquery: \"1.7.3pre\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\t// The number of elements contained in the matched element set\n\tsize: function() {\n\t\treturn this.length;\n\t},\n\n\ttoArray: function() {\n\t\treturn slice.call( this, 0 );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num == null ?\n\n\t\t\t// Return a 'clean' array\n\t\t\tthis.toArray() :\n\n\t\t\t// Return just the object\n\t\t\t( num < 0 ? this[ this.length + num ] : this[ num ] );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems, name, selector ) {\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = this.constructor();\n\n\t\tif ( jQuery.isArray( elems ) ) {\n\t\t\tpush.apply( ret, elems );\n\n\t\t} else {\n\t\t\tjQuery.merge( ret, elems );\n\t\t}\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\tret.context = this.context;\n\n\t\tif ( name === \"find\" ) {\n\t\t\tret.selector = this.selector + ( this.selector ? \" \" : \"\" ) + selector;\n\t\t} else if ( name ) {\n\t\t\tret.selector = this.selector + \".\" + name + \"(\" + selector + \")\";\n\t\t}\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\t// (You can seed the arguments with an array of args, but this is\n\t// only used internally.)\n\teach: function( callback, args ) {\n\t\treturn jQuery.each( this, callback, args );\n\t},\n\n\tready: function( fn ) {\n\t\t// Attach the listeners\n\t\tjQuery.bindReady();\n\n\t\t// Add the callback\n\t\treadyList.add( fn );\n\n\t\treturn this;\n\t},\n\n\teq: function( i ) {\n\t\ti = +i;\n\t\treturn i === -1 ?\n\t\t\tthis.slice( i ) :\n\t\t\tthis.slice( i, i + 1 );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ),\n\t\t\t\"slice\", slice.call(arguments).join(\",\") );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map(this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t}));\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor(null);\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: [].sort,\n\tsplice: [].splice\n};\n\n// Give the init function the jQuery prototype for later instantiation\njQuery.fn.init.prototype = jQuery.fn;\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[0] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\t\ttarget = arguments[1] || {};\n\t\t// skip the boolean and the target\n\t\ti = 2;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n\t\ttarget = {};\n\t}\n\n\t// extend jQuery itself if only one argument is passed\n\tif ( length === i ) {\n\t\ttarget = this;\n\t\t--i;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\t\t// Only deal with non-null/undefined values\n\t\tif ( (options = arguments[ i ]) != null ) {\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && jQuery.isArray(src) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject(src) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend({\n\tnoConflict: function( deep ) {\n\t\tif ( window.$ === jQuery ) {\n\t\t\twindow.$ = _$;\n\t\t}\n\n\t\tif ( deep && window.jQuery === jQuery ) {\n\t\t\twindow.jQuery = _jQuery;\n\t\t}\n\n\t\treturn jQuery;\n\t},\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Hold (or release) the ready event\n\tholdReady: function( hold ) {\n\t\tif ( hold ) {\n\t\t\tjQuery.readyWait++;\n\t\t} else {\n\t\t\tjQuery.ready( true );\n\t\t}\n\t},\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\t\t// Either a released hold or an DOMready/load event and not yet ready\n\t\tif ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {\n\t\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\t\tif ( !document.body ) {\n\t\t\t\treturn setTimeout( jQuery.ready, 1 );\n\t\t\t}\n\n\t\t\t// Remember that the DOM is ready\n\t\t\tjQuery.isReady = true;\n\n\t\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If there are functions bound, to execute\n\t\t\treadyList.fireWith( document, [ jQuery ] );\n\n\t\t\t// Trigger any bound ready events\n\t\t\tif ( jQuery.fn.trigger ) {\n\t\t\t\tjQuery( document ).trigger( \"ready\" ).off( \"ready\" );\n\t\t\t}\n\t\t}\n\t},\n\n\tbindReady: function() {\n\t\tif ( readyList ) {\n\t\t\treturn;\n\t\t}\n\n\t\treadyList = jQuery.Callbacks( \"once memory\" );\n\n\t\t// Catch cases where $(document).ready() is called after the\n\t\t// browser event has already occurred.\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\treturn setTimeout( jQuery.ready, 1 );\n\t\t}\n\n\t\t// Mozilla, Opera and webkit nightlies currently support this event\n\t\tif ( document.addEventListener ) {\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", jQuery.ready, false );\n\n\t\t// If IE event model is used\n\t\t} else if ( document.attachEvent ) {\n\t\t\t// ensure firing before onload,\n\t\t\t// maybe late but safe also for iframes\n\t\t\tdocument.attachEvent( \"onreadystatechange\", DOMContentLoaded );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.attachEvent( \"onload\", jQuery.ready );\n\n\t\t\t// If IE and not a frame\n\t\t\t// continually check to see if the document is ready\n\t\t\tvar toplevel = false;\n\n\t\t\ttry {\n\t\t\t\ttoplevel = window.frameElement == null;\n\t\t\t} catch(e) {}\n\n\t\t\tif ( document.documentElement.doScroll && toplevel ) {\n\t\t\t\tdoScrollCheck();\n\t\t\t}\n\t\t}\n\t},\n\n\t// See test/unit/core.js for details concerning isFunction.\n\t// Since version 1.3, DOM methods and functions like alert\n\t// aren't supported. They return false on IE (#2968).\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type(obj) === \"function\";\n\t},\n\n\tisArray: Array.isArray || function( obj ) {\n\t\treturn jQuery.type(obj) === \"array\";\n\t},\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj == obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\t\treturn !isNaN( parseFloat(obj) ) && isFinite( obj );\n\t},\n\n\ttype: function( obj ) {\n\t\treturn obj == null ?\n\t\t\tString( obj ) :\n\t\t\tclass2type[ toString.call(obj) ] || \"object\";\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\t// Must be an Object.\n\t\t// Because of IE, we also have to check the presence of the constructor property.\n\t\t// Make sure that DOM nodes and window objects don't pass through, as well\n\t\tif ( !obj || jQuery.type(obj) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\t// Not own constructor property must be Object\n\t\t\tif ( obj.constructor &&\n\t\t\t\t!hasOwn.call(obj, \"constructor\") &&\n\t\t\t\t!hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\t// IE8,9 Will throw exceptions on certain host objects #9897\n\t\t\treturn false;\n\t\t}\n\n\t\t// Own properties are enumerated firstly, so to speed up,\n\t\t// if last one is own, then all properties are own.\n\n\t\tvar key;\n\t\tfor ( key in obj ) {}\n\n\t\treturn key === undefined || hasOwn.call( obj, key );\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tfor ( var name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tparseJSON: function( data ) {\n\t\tif ( typeof data !== \"string\" || !data ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Make sure leading/trailing whitespace is removed (IE can't handle it)\n\t\tdata = jQuery.trim( data );\n\n\t\t// Attempt to parse using the native JSON parser first\n\t\tif ( window.JSON && window.JSON.parse ) {\n\t\t\treturn window.JSON.parse( data );\n\t\t}\n\n\t\t// Make sure the incoming data is actual JSON\n\t\t// Logic borrowed from http://json.org/json2.js\n\t\tif ( rvalidchars.test( data.replace( rvalidescape, \"@\" )\n\t\t\t.replace( rvalidtokens, \"]\" )\n\t\t\t.replace( rvalidbraces, \"\")) ) {\n\n\t\t\treturn ( new Function( \"return \" + data ) )();\n\n\t\t}\n\t\tjQuery.error( \"Invalid JSON: \" + data );\n\t},\n\n\t// Cross-browser xml parsing\n\tparseXML: function( data ) {\n\t\tif ( typeof data !== \"string\" || !data ) {\n\t\t\treturn null;\n\t\t}\n\t\tvar xml, tmp;\n\t\ttry {\n\t\t\tif ( window.DOMParser ) { // Standard\n\t\t\t\ttmp = new DOMParser();\n\t\t\t\txml = tmp.parseFromString( data , \"text/xml\" );\n\t\t\t} else { // IE\n\t\t\t\txml = new ActiveXObject( \"Microsoft.XMLDOM\" );\n\t\t\t\txml.async = \"false\";\n\t\t\t\txml.loadXML( data );\n\t\t\t}\n\t\t} catch( e ) {\n\t\t\txml = undefined;\n\t\t}\n\t\tif ( !xml || !xml.documentElement || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\t\tjQuery.error( \"Invalid XML: \" + data );\n\t\t}\n\t\treturn xml;\n\t},\n\n\tnoop: function() {},\n\n\t// Evaluates a script in a global context\n\t// Workarounds based on findings by Jim Driscoll\n\t// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context\n\tglobalEval: function( data ) {\n\t\tif ( data && rnotwhite.test( data ) ) {\n\t\t\t// We use execScript on Internet Explorer\n\t\t\t// We use an anonymous function so that context is window\n\t\t\t// rather than jQuery in Firefox\n\t\t\t( window.execScript || function( data ) {\n\t\t\t\twindow[ \"eval\" ].call( window, data );\n\t\t\t} )( data );\n\t\t}\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();\n\t},\n\n\t// args is for internal usage only\n\teach: function( object, callback, args ) {\n\t\tvar name, i = 0,\n\t\t\tlength = object.length,\n\t\t\tisObj = length === undefined || jQuery.isFunction( object );\n\n\t\tif ( args ) {\n\t\t\tif ( isObj ) {\n\t\t\t\tfor ( name in object ) {\n\t\t\t\t\tif ( callback.apply( object[ name ], args ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( ; i < length; ) {\n\t\t\t\t\tif ( callback.apply( object[ i++ ], args ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// A special, fast, case for the most common use of each\n\t\t} else {\n\t\t\tif ( isObj ) {\n\t\t\t\tfor ( name in object ) {\n\t\t\t\t\tif ( callback.call( object[ name ], name, object[ name ] ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( ; i < length; ) {\n\t\t\t\t\tif ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn object;\n\t},\n\n\t// Use native String.trim function wherever possible\n\ttrim: trim ?\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\ttrim.call( text );\n\t\t} :\n\n\t\t// Otherwise use our own trimming functionality\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\ttext.toString().replace( trimLeft, \"\" ).replace( trimRight, \"\" );\n\t\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( array, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( array != null ) {\n\t\t\t// The window, strings (and functions) also have 'length'\n\t\t\t// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930\n\t\t\tvar type = jQuery.type( array );\n\n\t\t\tif ( array.length == null || type === \"string\" || type === \"function\" || type === \"regexp\" || jQuery.isWindow( array ) ) {\n\t\t\t\tpush.call( ret, array );\n\t\t\t} else {\n\t\t\t\tjQuery.merge( ret, array );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, array, i ) {\n\t\tvar len;\n\n\t\tif ( array ) {\n\t\t\tif ( indexOf ) {\n\t\t\t\treturn indexOf.call( array, elem, i );\n\t\t\t}\n\n\t\t\tlen = array.length;\n\t\t\ti = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t// Skip accessing in sparse arrays\n\t\t\t\tif ( i in array && array[ i ] === elem ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar i = first.length,\n\t\t\tj = 0;\n\n\t\tif ( typeof second.length === \"number\" ) {\n\t\t\tfor ( var l = second.length; j < l; j++ ) {\n\t\t\t\tfirst[ i++ ] = second[ j ];\n\t\t\t}\n\n\t\t} else {\n\t\t\twhile ( second[j] !== undefined ) {\n\t\t\t\tfirst[ i++ ] = second[ j++ ];\n\t\t\t}\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, inv ) {\n\t\tvar ret = [], retVal;\n\t\tinv = !!inv;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( var i = 0, length = elems.length; i < length; i++ ) {\n\t\t\tretVal = !!callback( elems[ i ], i );\n\t\t\tif ( inv !== retVal ) {\n\t\t\t\tret.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar value, key, ret = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\t// jquery objects are treated as arrays\n\t\t\tisArray = elems instanceof jQuery || length !== undefined && typeof length === \"number\" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;\n\n\t\t// Go through the array, translating each of the items to their\n\t\tif ( isArray ) {\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret[ ret.length ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( key in elems ) {\n\t\t\t\tvalue = callback( elems[ key ], key, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret[ ret.length ] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn ret.concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tif ( typeof context === \"string\" ) {\n\t\t\tvar tmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\tvar args = slice.call( arguments, 2 ),\n\t\t\tproxy = function() {\n\t\t\t\treturn fn.apply( context, args.concat( slice.call( arguments ) ) );\n\t\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\t// Multifunctional method to get and set values of a collection\n\t// The value/s can optionally be executed if it's a function\n\taccess: function( elems, fn, key, value, chainable, emptyGet, pass ) {\n\t\tvar exec,\n\t\t\tbulk = key == null,\n\t\t\ti = 0,\n\t\t\tlength = elems.length;\n\n\t\t// Sets many values\n\t\tif ( key && typeof key === \"object\" ) {\n\t\t\tfor ( i in key ) {\n\t\t\t\tjQuery.access( elems, fn, i, key[i], 1, emptyGet, value );\n\t\t\t}\n\t\t\tchainable = 1;\n\n\t\t// Sets one value\n\t\t} else if ( value !== undefined ) {\n\t\t\t// Optionally, function values get executed if exec is true\n\t\t\texec = pass === undefined && jQuery.isFunction( value );\n\n\t\t\tif ( bulk ) {\n\t\t\t\t// Bulk operations only iterate when executing function values\n\t\t\t\tif ( exec ) {\n\t\t\t\t\texec = fn;\n\t\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\t\treturn exec.call( jQuery( elem ), value );\n\t\t\t\t\t};\n\n\t\t\t\t// Otherwise they run against the entire set\n\t\t\t\t} else {\n\t\t\t\t\tfn.call( elems, value );\n\t\t\t\t\tfn = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( fn ) {\n\t\t\t\tfor (; i < length; i++ ) {\n\t\t\t\t\tfn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tchainable = 1;\n\t\t}\n\n\t\treturn chainable ?\n\t\t\telems :\n\n\t\t\t// Gets\n\t\t\tbulk ?\n\t\t\t\tfn.call( elems ) :\n\t\t\t\tlength ? fn( elems[0], key ) : emptyGet;\n\t},\n\n\tnow: function() {\n\t\treturn ( new Date() ).getTime();\n\t},\n\n\t// Use of jQuery.browser is frowned upon.\n\t// More details: http://docs.jquery.com/Utilities/jQuery.browser\n\tuaMatch: function( ua ) {\n\t\tua = ua.toLowerCase();\n\n\t\tvar match = rwebkit.exec( ua ) ||\n\t\t\tropera.exec( ua ) ||\n\t\t\trmsie.exec( ua ) ||\n\t\t\tua.indexOf(\"compatible\") < 0 && rmozilla.exec( ua ) ||\n\t\t\t[];\n\n\t\treturn { browser: match[1] || \"\", version: match[2] || \"0\" };\n\t},\n\n\tsub: function() {\n\t\tfunction jQuerySub( selector, context ) {\n\t\t\treturn new jQuerySub.fn.init( selector, context );\n\t\t}\n\t\tjQuery.extend( true, jQuerySub, this );\n\t\tjQuerySub.superclass = this;\n\t\tjQuerySub.fn = jQuerySub.prototype = this();\n\t\tjQuerySub.fn.constructor = jQuerySub;\n\t\tjQuerySub.sub = this.sub;\n\t\tjQuerySub.fn.init = function init( selector, context ) {\n\t\t\tif ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {\n\t\t\t\tcontext = jQuerySub( context );\n\t\t\t}\n\n\t\t\treturn jQuery.fn.init.call( this, selector, context, rootjQuerySub );\n\t\t};\n\t\tjQuerySub.fn.init.prototype = jQuerySub.fn;\n\t\tvar rootjQuerySub = jQuerySub(document);\n\t\treturn jQuerySub;\n\t},\n\n\tbrowser: {}\n});\n\n// Populate the class2type map\njQuery.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"), function(i, name) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n});\n\nbrowserMatch = jQuery.uaMatch( userAgent );\nif ( browserMatch.browser ) {\n\tjQuery.browser[ browserMatch.browser ] = true;\n\tjQuery.browser.version = browserMatch.version;\n}\n\n// Deprecated, use jQuery.browser.webkit instead\nif ( jQuery.browser.webkit ) {\n\tjQuery.browser.safari = true;\n}\n\n// IE doesn't match non-breaking spaces with \\s\nif ( rnotwhite.test( \"\\xA0\" ) ) {\n\ttrimLeft = /^[\\s\\xA0]+/;\n\ttrimRight = /[\\s\\xA0]+$/;\n}\n\n// All jQuery objects should point back to these\nrootjQuery = jQuery(document);\n\n// Cleanup functions for the document ready method\nif ( document.addEventListener ) {\n\tDOMContentLoaded = function() {\n\t\tdocument.removeEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\t\tjQuery.ready();\n\t};\n\n} else if ( document.attachEvent ) {\n\tDOMContentLoaded = function() {\n\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\tdocument.detachEvent( \"onreadystatechange\", DOMContentLoaded );\n\t\t\tjQuery.ready();\n\t\t}\n\t};\n}\n\n// The DOM ready check for Internet Explorer\nfunction doScrollCheck() {\n\tif ( jQuery.isReady ) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\t// If IE is used, use the trick by Diego Perini\n\t\t// http://javascript.nwbox.com/IEContentLoaded/\n\t\tdocument.documentElement.doScroll(\"left\");\n\t} catch(e) {\n\t\tsetTimeout( doScrollCheck, 1 );\n\t\treturn;\n\t}\n\n\t// and execute any waiting functions\n\tjQuery.ready();\n}\n\nreturn jQuery;\n\n})();\n\n\n// String to Object flags format cache\nvar flagsCache = {};\n\n// Convert String-formatted flags into Object-formatted ones and store in cache\nfunction createFlags( flags ) {\n\tvar object = flagsCache[ flags ] = {},\n\t\ti, length;\n\tflags = flags.split( /\\s+/ );\n\tfor ( i = 0, length = flags.length; i < length; i++ ) {\n\t\tobject[ flags[i] ] = true;\n\t}\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\tflags:\tan optional list of space-separated flags that will change how\n *\t\t\tthe callback list behaves\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible flags:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( flags ) {\n\n\t// Convert flags from String-formatted to Object-formatted\n\t// (we check in cache first)\n\tflags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};\n\n\tvar // Actual callback list\n\t\tlist = [],\n\t\t// Stack of fire calls for repeatable lists\n\t\tstack = [],\n\t\t// Last fire value (for non-forgettable lists)\n\t\tmemory,\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\t\t// Flag to know if list is currently firing\n\t\tfiring,\n\t\t// First callback to fire (used internally by add and fireWith)\n\t\tfiringStart,\n\t\t// End of the loop when firing\n\t\tfiringLength,\n\t\t// Index of currently firing callback (modified by remove if needed)\n\t\tfiringIndex,\n\t\t// Add one or several callbacks to the list\n\t\tadd = function( args ) {\n\t\t\tvar i,\n\t\t\t\tlength,\n\t\t\t\telem,\n\t\t\t\ttype,\n\t\t\t\tactual;\n\t\t\tfor ( i = 0, length = args.length; i < length; i++ ) {\n\t\t\t\telem = args[ i ];\n\t\t\t\ttype = jQuery.type( elem );\n\t\t\t\tif ( type === \"array\" ) {\n\t\t\t\t\t// Inspect recursively\n\t\t\t\t\tadd( elem );\n\t\t\t\t} else if ( type === \"function\" ) {\n\t\t\t\t\t// Add if not in unique mode and callback is not in\n\t\t\t\t\tif ( !flags.unique || !self.has( elem ) ) {\n\t\t\t\t\t\tlist.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// Fire callbacks\n\t\tfire = function( context, args ) {\n\t\t\targs = args || [];\n\t\t\tmemory = !flags.memory || [ context, args ];\n\t\t\tfired = true;\n\t\t\tfiring = true;\n\t\t\tfiringIndex = firingStart || 0;\n\t\t\tfiringStart = 0;\n\t\t\tfiringLength = list.length;\n\t\t\tfor ( ; list && firingIndex < firingLength; firingIndex++ ) {\n\t\t\t\tif ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {\n\t\t\t\t\tmemory = true; // Mark as halted\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiring = false;\n\t\t\tif ( list ) {\n\t\t\t\tif ( !flags.once ) {\n\t\t\t\t\tif ( stack && stack.length ) {\n\t\t\t\t\t\tmemory = stack.shift();\n\t\t\t\t\t\tself.fireWith( memory[ 0 ], memory[ 1 ] );\n\t\t\t\t\t}\n\t\t\t\t} else if ( memory === true ) {\n\t\t\t\t\tself.disable();\n\t\t\t\t} else {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// Actual Callbacks object\n\t\tself = {\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tvar length = list.length;\n\t\t\t\t\tadd( arguments );\n\t\t\t\t\t// Do we need to add the callbacks to the\n\t\t\t\t\t// current firing batch?\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tfiringLength = list.length;\n\t\t\t\t\t// With memory, if we're not firing then\n\t\t\t\t\t// we should call right away, unless previous\n\t\t\t\t\t// firing was halted (stopOnFalse)\n\t\t\t\t\t} else if ( memory && memory !== true ) {\n\t\t\t\t\t\tfiringStart = length;\n\t\t\t\t\t\tfire( memory[ 0 ], memory[ 1 ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tvar args = arguments,\n\t\t\t\t\t\targIndex = 0,\n\t\t\t\t\t\targLength = args.length;\n\t\t\t\t\tfor ( ; argIndex < argLength ; argIndex++ ) {\n\t\t\t\t\t\tfor ( var i = 0; i < list.length; i++ ) {\n\t\t\t\t\t\t\tif ( args[ argIndex ] === list[ i ] ) {\n\t\t\t\t\t\t\t\t// Handle firingIndex and firingLength\n\t\t\t\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\t\t\t\tif ( i <= firingLength ) {\n\t\t\t\t\t\t\t\t\t\tfiringLength--;\n\t\t\t\t\t\t\t\t\t\tif ( i <= firingIndex ) {\n\t\t\t\t\t\t\t\t\t\t\tfiringIndex--;\n\t\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}\n\t\t\t\t\t\t\t\t// Remove the element\n\t\t\t\t\t\t\t\tlist.splice( i--, 1 );\n\t\t\t\t\t\t\t\t// If we have some unicity property then\n\t\t\t\t\t\t\t\t// we only need to do this once\n\t\t\t\t\t\t\t\tif ( flags.unique ) {\n\t\t\t\t\t\t\t\t\tbreak;\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\treturn this;\n\t\t\t},\n\t\t\t// Control if a given callback is in the list\n\t\t\thas: function( fn ) {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tvar i = 0,\n\t\t\t\t\t\tlength = list.length;\n\t\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\t\tif ( fn === list[ i ] ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tlist = [];\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Have the list do nothing anymore\n\t\t\tdisable: function() {\n\t\t\t\tlist = stack = memory = undefined;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it disabled?\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\t\t\t// Lock the list in its current state\n\t\t\tlock: function() {\n\t\t\t\tstack = undefined;\n\t\t\t\tif ( !memory || memory === true ) {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it locked?\n\t\t\tlocked: function() {\n\t\t\t\treturn !stack;\n\t\t\t},\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( stack ) {\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tif ( !flags.once ) {\n\t\t\t\t\t\t\tstack.push( [ context, args ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if ( !( flags.once && memory ) ) {\n\t\t\t\t\t\tfire( context, args );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\n\n\nvar // Static reference to slice\n\tsliceDeferred = [].slice;\n\njQuery.extend({\n\n\tDeferred: function( func ) {\n\t\tvar doneList = jQuery.Callbacks( \"once memory\" ),\n\t\t\tfailList = jQuery.Callbacks( \"once memory\" ),\n\t\t\tprogressList = jQuery.Callbacks( \"memory\" ),\n\t\t\tstate = \"pending\",\n\t\t\tlists = {\n\t\t\t\tresolve: doneList,\n\t\t\t\treject: failList,\n\t\t\t\tnotify: progressList\n\t\t\t},\n\t\t\tpromise = {\n\t\t\t\tdone: doneList.add,\n\t\t\t\tfail: failList.add,\n\t\t\t\tprogress: progressList.add,\n\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\n\t\t\t\t// Deprecated\n\t\t\t\tisResolved: doneList.fired,\n\t\t\t\tisRejected: failList.fired,\n\n\t\t\t\tthen: function( doneCallbacks, failCallbacks, progressCallbacks ) {\n\t\t\t\t\tdeferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tpipe: function( fnDone, fnFail, fnProgress ) {\n\t\t\t\t\treturn jQuery.Deferred(function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( {\n\t\t\t\t\t\t\tdone: [ fnDone, \"resolve\" ],\n\t\t\t\t\t\t\tfail: [ fnFail, \"reject\" ],\n\t\t\t\t\t\t\tprogress: [ fnProgress, \"notify\" ]\n\t\t\t\t\t\t}, function( handler, data ) {\n\t\t\t\t\t\t\tvar fn = data[ 0 ],\n\t\t\t\t\t\t\t\taction = data[ 1 ],\n\t\t\t\t\t\t\t\treturned;\n\t\t\t\t\t\t\tif ( jQuery.isFunction( fn ) ) {\n\t\t\t\t\t\t\t\tdeferred[ handler ](function() {\n\t\t\t\t\t\t\t\t\treturned = fn.apply( this, arguments );\n\t\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\t\treturned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tnewDefer[ action + \"With\" ]( this === deferred ? newDefer : this, [ returned ] );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdeferred[ handler ]( newDefer[ action ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}).promise();\n\t\t\t\t},\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\tif ( obj == null ) {\n\t\t\t\t\t\tobj = promise;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor ( var key in promise ) {\n\t\t\t\t\t\t\tobj[ key ] = promise[ key ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn obj;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = promise.promise({}),\n\t\t\tkey;\n\n\t\tfor ( key in lists ) {\n\t\t\tdeferred[ key ] = lists[ key ].fire;\n\t\t\tdeferred[ key + \"With\" ] = lists[ key ].fireWith;\n\t\t}\n\n\t\t// Handle state\n\t\tdeferred.done( function() {\n\t\t\tstate = \"resolved\";\n\t\t}, failList.disable, progressList.lock ).fail( function() {\n\t\t\tstate = \"rejected\";\n\t\t}, doneList.disable, progressList.lock );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( firstParam ) {\n\t\tvar args = sliceDeferred.call( arguments, 0 ),\n\t\t\ti = 0,\n\t\t\tlength = args.length,\n\t\t\tpValues = new Array( length ),\n\t\t\tcount = length,\n\t\t\tpCount = length,\n\t\t\tdeferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?\n\t\t\t\tfirstParam :\n\t\t\t\tjQuery.Deferred(),\n\t\t\tpromise = deferred.promise();\n\t\tfunction resolveFunc( i ) {\n\t\t\treturn function( value ) {\n\t\t\t\targs[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdeferred.resolveWith( deferred, args );\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\tfunction progressFunc( i ) {\n\t\t\treturn function( value ) {\n\t\t\t\tpValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;\n\t\t\t\tdeferred.notifyWith( promise, pValues );\n\t\t\t};\n\t\t}\n\t\tif ( length > 1 ) {\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {\n\t\t\t\t\targs[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );\n\t\t\t\t} else {\n\t\t\t\t\t--count;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( !count ) {\n\t\t\t\tdeferred.resolveWith( deferred, args );\n\t\t\t}\n\t\t} else if ( deferred !== firstParam ) {\n\t\t\tdeferred.resolveWith( deferred, length ? [ firstParam ] : [] );\n\t\t}\n\t\treturn promise;\n\t}\n});\n\n\n\n\njQuery.support = (function() {\n\n\tvar support,\n\t\tall,\n\t\ta,\n\t\tselect,\n\t\topt,\n\t\tinput,\n\t\tfragment,\n\t\ttds,\n\t\tevents,\n\t\teventName,\n\t\ti,\n\t\tisSupported,\n\t\tdiv = document.createElement( \"div\" ),\n\t\tdocumentElement = document.documentElement;\n\n\t// Preliminary tests\n\tdiv.setAttribute(\"className\", \"t\");\n\tdiv.innerHTML = \"   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>\";\n\n\tall = div.getElementsByTagName( \"*\" );\n\ta = div.getElementsByTagName( \"a\" )[ 0 ];\n\n\t// Can't get basic test support\n\tif ( !all || !all.length || !a ) {\n\t\treturn {};\n\t}\n\n\t// First batch of supports tests\n\tselect = document.createElement( \"select\" );\n\topt = select.appendChild( document.createElement(\"option\") );\n\tinput = div.getElementsByTagName( \"input\" )[ 0 ];\n\n\tsupport = {\n\t\t// IE strips leading whitespace when .innerHTML is used\n\t\tleadingWhitespace: ( div.firstChild.nodeType === 3 ),\n\n\t\t// Make sure that tbody elements aren't automatically inserted\n\t\t// IE will insert them into empty tables\n\t\ttbody: !div.getElementsByTagName(\"tbody\").length,\n\n\t\t// Make sure that link elements get serialized correctly by innerHTML\n\t\t// This requires a wrapper element in IE\n\t\thtmlSerialize: !!div.getElementsByTagName(\"link\").length,\n\n\t\t// Get the style information from getAttribute\n\t\t// (IE uses .cssText instead)\n\t\tstyle: /top/.test( a.getAttribute(\"style\") ),\n\n\t\t// Make sure that URLs aren't manipulated\n\t\t// (IE normalizes it by default)\n\t\threfNormalized: ( a.getAttribute(\"href\") === \"/a\" ),\n\n\t\t// Make sure that element opacity exists\n\t\t// (IE uses filter instead)\n\t\t// Use a regex to work around a WebKit issue. See #5145\n\t\topacity: /^0.55/.test( a.style.opacity ),\n\n\t\t// Verify style float existence\n\t\t// (IE uses styleFloat instead of cssFloat)\n\t\tcssFloat: !!a.style.cssFloat,\n\n\t\t// Make sure that if no value is specified for a checkbox\n\t\t// that it defaults to \"on\".\n\t\t// (WebKit defaults to \"\" instead)\n\t\tcheckOn: ( input.value === \"on\" ),\n\n\t\t// Make sure that a selected-by-default option has a working selected property.\n\t\t// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)\n\t\toptSelected: opt.selected,\n\n\t\t// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)\n\t\tgetSetAttribute: div.className !== \"t\",\n\n\t\t// Tests for enctype support on a form(#6743)\n\t\tenctype: !!document.createElement(\"form\").enctype,\n\n\t\t// Makes sure cloning an html5 element does not cause problems\n\t\t// Where outerHTML is undefined, this still works\n\t\thtml5Clone: document.createElement(\"nav\").cloneNode( true ).outerHTML !== \"<:nav></:nav>\",\n\n\t\t// Will be defined later\n\t\tsubmitBubbles: true,\n\t\tchangeBubbles: true,\n\t\tfocusinBubbles: false,\n\t\tdeleteExpando: true,\n\t\tnoCloneEvent: true,\n\t\tinlineBlockNeedsLayout: false,\n\t\tshrinkWrapBlocks: false,\n\t\treliableMarginRight: true,\n\t\tpixelMargin: true\n\t};\n\n\t// jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead\n\tjQuery.boxModel = support.boxModel = (document.compatMode === \"CSS1Compat\");\n\n\t// Make sure checked status is properly cloned\n\tinput.checked = true;\n\tsupport.noCloneChecked = input.cloneNode( true ).checked;\n\n\t// Make sure that the options inside disabled selects aren't marked as disabled\n\t// (WebKit marks them as disabled)\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Test to see if it's possible to delete an expando from an element\n\t// Fails in Internet Explorer\n\ttry {\n\t\tdelete div.test;\n\t} catch( e ) {\n\t\tsupport.deleteExpando = false;\n\t}\n\n\tif ( !div.addEventListener && div.attachEvent && div.fireEvent ) {\n\t\tdiv.attachEvent( \"onclick\", function() {\n\t\t\t// Cloning a node shouldn't copy over any\n\t\t\t// bound event handlers (IE does this)\n\t\t\tsupport.noCloneEvent = false;\n\t\t});\n\t\tdiv.cloneNode( true ).fireEvent( \"onclick\" );\n\t}\n\n\t// Check if a radio maintains its value\n\t// after being appended to the DOM\n\tinput = document.createElement(\"input\");\n\tinput.value = \"t\";\n\tinput.setAttribute(\"type\", \"radio\");\n\tsupport.radioValue = input.value === \"t\";\n\n\tinput.setAttribute(\"checked\", \"checked\");\n\n\t// #11217 - WebKit loses check when the name is after the checked attribute\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\tfragment = document.createDocumentFragment();\n\tfragment.appendChild( div.lastChild );\n\n\t// WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Check if a disconnected checkbox will retain its checked\n\t// value of true after appended to the DOM (IE6/7)\n\tsupport.appendChecked = input.checked;\n\n\tfragment.removeChild( input );\n\tfragment.appendChild( div );\n\n\t// Technique from Juriy Zaytsev\n\t// http://perfectionkills.com/detecting-event-support-without-browser-sniffing/\n\t// We only care about the case where non-standard event systems\n\t// are used, namely in IE. Short-circuiting here helps us to\n\t// avoid an eval call (in setAttribute) which can cause CSP\n\t// to go haywire. See: https://developer.mozilla.org/en/Security/CSP\n\tif ( div.attachEvent ) {\n\t\tfor ( i in {\n\t\t\tsubmit: 1,\n\t\t\tchange: 1,\n\t\t\tfocusin: 1\n\t\t}) {\n\t\t\teventName = \"on\" + i;\n\t\t\tisSupported = ( eventName in div );\n\t\t\tif ( !isSupported ) {\n\t\t\t\tdiv.setAttribute( eventName, \"return;\" );\n\t\t\t\tisSupported = ( typeof div[ eventName ] === \"function\" );\n\t\t\t}\n\t\t\tsupport[ i + \"Bubbles\" ] = isSupported;\n\t\t}\n\t}\n\n\tfragment.removeChild( div );\n\n\t// Null elements to avoid leaks in IE\n\tfragment = select = opt = div = input = null;\n\n\t// Run tests that need a body at doc ready\n\tjQuery(function() {\n\t\tvar container, outer, inner, table, td, offsetSupport,\n\t\t\tmarginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,\n\t\t\tpaddingMarginBorderVisibility, paddingMarginBorder,\n\t\t\tbody = document.getElementsByTagName(\"body\")[0];\n\n\t\tif ( !body ) {\n\t\t\t// Return for frameset docs that don't have a body\n\t\t\treturn;\n\t\t}\n\n\t\tconMarginTop = 1;\n\t\tpaddingMarginBorder = \"padding:0;margin:0;border:\";\n\t\tpositionTopLeftWidthHeight = \"position:absolute;top:0;left:0;width:1px;height:1px;\";\n\t\tpaddingMarginBorderVisibility = paddingMarginBorder + \"0;visibility:hidden;\";\n\t\tstyle = \"style='\" + positionTopLeftWidthHeight + paddingMarginBorder + \"5px solid #000;\";\n\t\thtml = \"<div \" + style + \"display:block;'><div style='\" + paddingMarginBorder + \"0;display:block;overflow:hidden;'></div></div>\" +\n\t\t\t\"<table \" + style + \"' cellpadding='0' cellspacing='0'>\" +\n\t\t\t\"<tr><td></td></tr></table>\";\n\n\t\tcontainer = document.createElement(\"div\");\n\t\tcontainer.style.cssText = paddingMarginBorderVisibility + \"width:0;height:0;position:static;top:0;margin-top:\" + conMarginTop + \"px\";\n\t\tbody.insertBefore( container, body.firstChild );\n\n\t\t// Construct the test element\n\t\tdiv = document.createElement(\"div\");\n\t\tcontainer.appendChild( div );\n\n\t\t// Check if table cells still have offsetWidth/Height when they are set\n\t\t// to display:none and there are still other visible table cells in a\n\t\t// table row; if so, offsetWidth/Height are not reliable for use when\n\t\t// determining if an element has been hidden directly using\n\t\t// display:none (it is still safe to use offsets if a parent element is\n\t\t// hidden; don safety goggles and see bug #4512 for more information).\n\t\t// (only IE 8 fails this test)\n\t\tdiv.innerHTML = \"<table><tr><td style='\" + paddingMarginBorder + \"0;display:none'></td><td>t</td></tr></table>\";\n\t\ttds = div.getElementsByTagName( \"td\" );\n\t\tisSupported = ( tds[ 0 ].offsetHeight === 0 );\n\n\t\ttds[ 0 ].style.display = \"\";\n\t\ttds[ 1 ].style.display = \"none\";\n\n\t\t// Check if empty table cells still have offsetWidth/Height\n\t\t// (IE <= 8 fail this test)\n\t\tsupport.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );\n\n\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t// gets computed margin-right based on width of container. For more\n\t\t// info see bug #3333\n\t\t// Fails in WebKit before Feb 2011 nightlies\n\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\tif ( window.getComputedStyle ) {\n\t\t\tdiv.innerHTML = \"\";\n\t\t\tmarginDiv = document.createElement( \"div\" );\n\t\t\tmarginDiv.style.width = \"0\";\n\t\t\tmarginDiv.style.marginRight = \"0\";\n\t\t\tdiv.style.width = \"2px\";\n\t\t\tdiv.appendChild( marginDiv );\n\t\t\tsupport.reliableMarginRight =\n\t\t\t\t( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;\n\t\t}\n\n\t\tif ( typeof div.style.zoom !== \"undefined\" ) {\n\t\t\t// Check if natively block-level elements act like inline-block\n\t\t\t// elements when setting their display to 'inline' and giving\n\t\t\t// them layout\n\t\t\t// (IE < 8 does this)\n\t\t\tdiv.innerHTML = \"\";\n\t\t\tdiv.style.width = div.style.padding = \"1px\";\n\t\t\tdiv.style.border = 0;\n\t\t\tdiv.style.overflow = \"hidden\";\n\t\t\tdiv.style.display = \"inline\";\n\t\t\tdiv.style.zoom = 1;\n\t\t\tsupport.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );\n\n\t\t\t// Check if elements with layout shrink-wrap their children\n\t\t\t// (IE 6 does this)\n\t\t\tdiv.style.display = \"block\";\n\t\t\tdiv.style.overflow = \"visible\";\n\t\t\tdiv.innerHTML = \"<div style='width:5px;'></div>\";\n\t\t\tsupport.shrinkWrapBlocks = ( div.offsetWidth !== 3 );\n\t\t}\n\n\t\tdiv.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;\n\t\tdiv.innerHTML = html;\n\n\t\touter = div.firstChild;\n\t\tinner = outer.firstChild;\n\t\ttd = outer.nextSibling.firstChild.firstChild;\n\n\t\toffsetSupport = {\n\t\t\tdoesNotAddBorder: ( inner.offsetTop !== 5 ),\n\t\t\tdoesAddBorderForTableAndCells: ( td.offsetTop === 5 )\n\t\t};\n\n\t\tinner.style.position = \"fixed\";\n\t\tinner.style.top = \"20px\";\n\n\t\t// safari subtracts parent border width here which is 5px\n\t\toffsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );\n\t\tinner.style.position = inner.style.top = \"\";\n\n\t\touter.style.overflow = \"hidden\";\n\t\touter.style.position = \"relative\";\n\n\t\toffsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );\n\t\toffsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );\n\n\t\tif ( window.getComputedStyle ) {\n\t\t\tdiv.style.marginTop = \"1%\";\n\t\t\tsupport.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== \"1%\";\n\t\t}\n\n\t\tif ( typeof container.style.zoom !== \"undefined\" ) {\n\t\t\tcontainer.style.zoom = 1;\n\t\t}\n\n\t\tbody.removeChild( container );\n\t\tmarginDiv = div = container = null;\n\n\t\tjQuery.extend( support, offsetSupport );\n\t});\n\n\treturn support;\n})();\n\n\n\n\nvar rbrace = /^(?:\\{.*\\}|\\[.*\\])$/,\n\trmultiDash = /([A-Z])/g;\n\njQuery.extend({\n\tcache: {},\n\n\t// Please use with caution\n\tuuid: 0,\n\n\t// Unique for each copy of jQuery on the page\n\t// Non-digits removed to match rinlinejQuery\n\texpando: \"jQuery\" + ( jQuery.fn.jquery + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// The following elements throw uncatchable exceptions if you\n\t// attempt to add expando properties to them.\n\tnoData: {\n\t\t\"embed\": true,\n\t\t// Ban all objects except for Flash (which handle expandos)\n\t\t\"object\": \"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",\n\t\t\"applet\": true\n\t},\n\n\thasData: function( elem ) {\n\t\telem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];\n\t\treturn !!elem && !isEmptyDataObject( elem );\n\t},\n\n\tdata: function( elem, name, data, pvt /* Internal Use Only */ ) {\n\t\tif ( !jQuery.acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar privateCache, thisCache, ret,\n\t\t\tinternalKey = jQuery.expando,\n\t\t\tgetByName = typeof name === \"string\",\n\n\t\t\t// We have to handle DOM nodes and JS objects differently because IE6-7\n\t\t\t// can't GC object references properly across the DOM-JS boundary\n\t\t\tisNode = elem.nodeType,\n\n\t\t\t// Only DOM nodes need the global jQuery cache; JS object data is\n\t\t\t// attached directly to the object so GC can occur automatically\n\t\t\tcache = isNode ? jQuery.cache : elem,\n\n\t\t\t// Only defining an ID for JS objects if its cache already exists allows\n\t\t\t// the code to shortcut on the same path as a DOM node with no cache\n\t\t\tid = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,\n\t\t\tisEvents = name === \"events\";\n\n\t\t// Avoid doing any more work than we need to when trying to get data on an\n\t\t// object that has no data at all\n\t\tif ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !id ) {\n\t\t\t// Only DOM nodes need a new unique ID for each element since their data\n\t\t\t// ends up in the global cache\n\t\t\tif ( isNode ) {\n\t\t\t\telem[ internalKey ] = id = ++jQuery.uuid;\n\t\t\t} else {\n\t\t\t\tid = internalKey;\n\t\t\t}\n\t\t}\n\n\t\tif ( !cache[ id ] ) {\n\t\t\tcache[ id ] = {};\n\n\t\t\t// Avoids exposing jQuery metadata on plain JS objects when the object\n\t\t\t// is serialized using JSON.stringify\n\t\t\tif ( !isNode ) {\n\t\t\t\tcache[ id ].toJSON = jQuery.noop;\n\t\t\t}\n\t\t}\n\n\t\t// An object can be passed to jQuery.data instead of a key/value pair; this gets\n\t\t// shallow copied over onto the existing cache\n\t\tif ( typeof name === \"object\" || typeof name === \"function\" ) {\n\t\t\tif ( pvt ) {\n\t\t\t\tcache[ id ] = jQuery.extend( cache[ id ], name );\n\t\t\t} else {\n\t\t\t\tcache[ id ].data = jQuery.extend( cache[ id ].data, name );\n\t\t\t}\n\t\t}\n\n\t\tprivateCache = thisCache = cache[ id ];\n\n\t\t// jQuery data() is stored in a separate object inside the object's internal data\n\t\t// cache in order to avoid key collisions between internal data and user-defined\n\t\t// data.\n\t\tif ( !pvt ) {\n\t\t\tif ( !thisCache.data ) {\n\t\t\t\tthisCache.data = {};\n\t\t\t}\n\n\t\t\tthisCache = thisCache.data;\n\t\t}\n\n\t\tif ( data !== undefined ) {\n\t\t\tthisCache[ jQuery.camelCase( name ) ] = data;\n\t\t}\n\n\t\t// Users should not attempt to inspect the internal events object using jQuery.data,\n\t\t// it is undocumented and subject to change. But does anyone listen? No.\n\t\tif ( isEvents && !thisCache[ name ] ) {\n\t\t\treturn privateCache.events;\n\t\t}\n\n\t\t// Check for both converted-to-camel and non-converted data property names\n\t\t// If a data property was specified\n\t\tif ( getByName ) {\n\n\t\t\t// First Try to find as-is property data\n\t\t\tret = thisCache[ name ];\n\n\t\t\t// Test for null|undefined property data\n\t\t\tif ( ret == null ) {\n\n\t\t\t\t// Try to find the camelCased property\n\t\t\t\tret = thisCache[ jQuery.camelCase( name ) ];\n\t\t\t}\n\t\t} else {\n\t\t\tret = thisCache;\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tremoveData: function( elem, name, pvt /* Internal Use Only */ ) {\n\t\tif ( !jQuery.acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar thisCache, i, l,\n\n\t\t\t// Reference to internal data cache key\n\t\t\tinternalKey = jQuery.expando,\n\n\t\t\tisNode = elem.nodeType,\n\n\t\t\t// See jQuery.data for more information\n\t\t\tcache = isNode ? jQuery.cache : elem,\n\n\t\t\t// See jQuery.data for more information\n\t\t\tid = isNode ? elem[ internalKey ] : internalKey;\n\n\t\t// If there is already no cache entry for this object, there is no\n\t\t// purpose in continuing\n\t\tif ( !cache[ id ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( name ) {\n\n\t\t\tthisCache = pvt ? cache[ id ] : cache[ id ].data;\n\n\t\t\tif ( thisCache ) {\n\n\t\t\t\t// Support array or space separated string names for data keys\n\t\t\t\tif ( !jQuery.isArray( name ) ) {\n\n\t\t\t\t\t// try the string as a key before any manipulation\n\t\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\t\tname = [ name ];\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// split the camel cased version by spaces unless a key with the spaces exists\n\t\t\t\t\t\tname = jQuery.camelCase( name );\n\t\t\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\t\t\tname = [ name ];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tname = name.split( \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor ( i = 0, l = name.length; i < l; i++ ) {\n\t\t\t\t\tdelete thisCache[ name[i] ];\n\t\t\t\t}\n\n\t\t\t\t// If there is no data left in the cache, we want to continue\n\t\t\t\t// and let the cache object itself get destroyed\n\t\t\t\tif ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// See jQuery.data for more information\n\t\tif ( !pvt ) {\n\t\t\tdelete cache[ id ].data;\n\n\t\t\t// Don't destroy the parent cache unless the internal data object\n\t\t\t// had been the only thing left in it\n\t\t\tif ( !isEmptyDataObject(cache[ id ]) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Browsers that fail expando deletion also refuse to delete expandos on\n\t\t// the window, but it will allow it on all other JS objects; other browsers\n\t\t// don't care\n\t\t// Ensure that `cache` is not a window object #10080\n\t\tif ( jQuery.support.deleteExpando || !cache.setInterval ) {\n\t\t\tdelete cache[ id ];\n\t\t} else {\n\t\t\tcache[ id ] = null;\n\t\t}\n\n\t\t// We destroyed the cache and need to eliminate the expando on the node to avoid\n\t\t// false lookups in the cache for entries that no longer exist\n\t\tif ( isNode ) {\n\t\t\t// IE does not allow us to delete expando properties from nodes,\n\t\t\t// nor does it have a removeAttribute function on Document nodes;\n\t\t\t// we must handle all of these cases\n\t\t\tif ( jQuery.support.deleteExpando ) {\n\t\t\t\tdelete elem[ internalKey ];\n\t\t\t} else if ( elem.removeAttribute ) {\n\t\t\t\telem.removeAttribute( internalKey );\n\t\t\t} else {\n\t\t\t\telem[ internalKey ] = null;\n\t\t\t}\n\t\t}\n\t},\n\n\t// For internal use only.\n\t_data: function( elem, name, data ) {\n\t\treturn jQuery.data( elem, name, data, true );\n\t},\n\n\t// A method for determining if a DOM node can handle the data expando\n\tacceptData: function( elem ) {\n\t\tif ( elem.nodeName ) {\n\t\t\tvar match = jQuery.noData[ elem.nodeName.toLowerCase() ];\n\n\t\t\tif ( match ) {\n\t\t\t\treturn !(match === true || elem.getAttribute(\"classid\") !== match);\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tvar parts, part, attr, name, l,\n\t\t\telem = this[0],\n\t\t\ti = 0,\n\t\t\tdata = null;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = jQuery.data( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !jQuery._data( elem, \"parsedAttrs\" ) ) {\n\t\t\t\t\tattr = elem.attributes;\n\t\t\t\t\tfor ( l = attr.length; i < l; i++ ) {\n\t\t\t\t\t\tname = attr[i].name;\n\n\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\tname = jQuery.camelCase( name.substring(5) );\n\n\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tjQuery._data( elem, \"parsedAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tjQuery.data( this, key );\n\t\t\t});\n\t\t}\n\n\t\tparts = key.split( \".\", 2 );\n\t\tparts[1] = parts[1] ? \".\" + parts[1] : \"\";\n\t\tpart = parts[1] + \"!\";\n\n\t\treturn jQuery.access( this, function( value ) {\n\n\t\t\tif ( value === undefined ) {\n\t\t\t\tdata = this.triggerHandler( \"getData\" + part, [ parts[0] ] );\n\n\t\t\t\t// Try to fetch any internally stored data first\n\t\t\t\tif ( data === undefined && elem ) {\n\t\t\t\t\tdata = jQuery.data( elem, key );\n\t\t\t\t\tdata = dataAttr( elem, key, data );\n\t\t\t\t}\n\n\t\t\t\treturn data === undefined && parts[1] ?\n\t\t\t\t\tthis.data( parts[0] ) :\n\t\t\t\t\tdata;\n\t\t\t}\n\n\t\t\tparts[1] = value;\n\t\t\tthis.each(function() {\n\t\t\t\tvar self = jQuery( this );\n\n\t\t\t\tself.triggerHandler( \"setData\" + part, parts );\n\t\t\t\tjQuery.data( this, key, value );\n\t\t\t\tself.triggerHandler( \"changeData\" + part, parts );\n\t\t\t});\n\t\t}, null, value, arguments.length > 1, null, false );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeData( this, key );\n\t\t});\n\t}\n});\n\nfunction dataAttr( elem, key, data ) {\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\n\t\tvar name = \"data-\" + key.replace( rmultiDash, \"-$1\" ).toLowerCase();\n\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = data === \"true\" ? true :\n\t\t\t\tdata === \"false\" ? false :\n\t\t\t\tdata === \"null\" ? null :\n\t\t\t\tjQuery.isNumeric( data ) ? +data :\n\t\t\t\t\trbrace.test( data ) ? jQuery.parseJSON( data ) :\n\t\t\t\t\tdata;\n\t\t\t} catch( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tjQuery.data( elem, key, data );\n\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\n\treturn data;\n}\n\n// checks a cache object for emptiness\nfunction isEmptyDataObject( obj ) {\n\tfor ( var name in obj ) {\n\n\t\t// if the public data object is empty, the private is still empty\n\t\tif ( name === \"data\" && jQuery.isEmptyObject( obj[name] ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( name !== \"toJSON\" ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n\n\n\nfunction handleQueueMarkDefer( elem, type, src ) {\n\tvar deferDataKey = type + \"defer\",\n\t\tqueueDataKey = type + \"queue\",\n\t\tmarkDataKey = type + \"mark\",\n\t\tdefer = jQuery._data( elem, deferDataKey );\n\tif ( defer &&\n\t\t( src === \"queue\" || !jQuery._data(elem, queueDataKey) ) &&\n\t\t( src === \"mark\" || !jQuery._data(elem, markDataKey) ) ) {\n\t\t// Give room for hard-coded callbacks to fire first\n\t\t// and eventually mark/queue something else on the element\n\t\tsetTimeout( function() {\n\t\t\tif ( !jQuery._data( elem, queueDataKey ) &&\n\t\t\t\t!jQuery._data( elem, markDataKey ) ) {\n\t\t\t\tjQuery.removeData( elem, deferDataKey, true );\n\t\t\t\tdefer.fire();\n\t\t\t}\n\t\t}, 0 );\n\t}\n}\n\njQuery.extend({\n\n\t_mark: function( elem, type ) {\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"mark\";\n\t\t\tjQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );\n\t\t}\n\t},\n\n\t_unmark: function( force, elem, type ) {\n\t\tif ( force !== true ) {\n\t\t\ttype = elem;\n\t\t\telem = force;\n\t\t\tforce = false;\n\t\t}\n\t\tif ( elem ) {\n\t\t\ttype = type || \"fx\";\n\t\t\tvar key = type + \"mark\",\n\t\t\t\tcount = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );\n\t\t\tif ( count ) {\n\t\t\t\tjQuery._data( elem, key, count );\n\t\t\t} else {\n\t\t\t\tjQuery.removeData( elem, key, true );\n\t\t\t\thandleQueueMarkDefer( elem, type, \"mark\" );\n\t\t\t}\n\t\t}\n\t},\n\n\tqueue: function( elem, type, data ) {\n\t\tvar q;\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tq = jQuery._data( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !q || jQuery.isArray(data) ) {\n\t\t\t\t\tq = jQuery._data( elem, type, jQuery.makeArray(data) );\n\t\t\t\t} else {\n\t\t\t\t\tq.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn q || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tfn = queue.shift(),\n\t\t\thooks = {};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\tjQuery._data( elem, type + \".run\", hooks );\n\t\t\tfn.call( elem, function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t}, hooks );\n\t\t}\n\n\t\tif ( !queue.length ) {\n\t\t\tjQuery.removeData( elem, type + \"queue \" + type + \".run\", true );\n\t\t\thandleQueueMarkDefer( elem, type, \"queue\" );\n\t\t}\n\t}\n});\n\njQuery.fn.extend({\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[0], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\tif ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t});\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t});\n\t},\n\t// Based off of the plugin by Clint Helfers, with permission.\n\t// http://blindsignals.com/index.php/2009/07/jquery-delay/\n\tdelay: function( time, type ) {\n\t\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\t\ttype = type || \"fx\";\n\n\t\treturn this.queue( type, function( next, hooks ) {\n\t\t\tvar timeout = setTimeout( next, time );\n\t\t\thooks.stop = function() {\n\t\t\t\tclearTimeout( timeout );\n\t\t\t};\n\t\t});\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, object ) {\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobject = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\t\tvar defer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = elements.length,\n\t\t\tcount = 1,\n\t\t\tdeferDataKey = type + \"defer\",\n\t\t\tqueueDataKey = type + \"queue\",\n\t\t\tmarkDataKey = type + \"mark\",\n\t\t\ttmp;\n\t\tfunction resolve() {\n\t\t\tif ( !( --count ) ) {\n\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t}\n\t\t}\n\t\twhile( i-- ) {\n\t\t\tif (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||\n\t\t\t\t\t( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||\n\t\t\t\t\t\tjQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&\n\t\t\t\t\tjQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( \"once memory\" ), true ) )) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( object );\n\t}\n});\n\n\n\n\nvar rclass = /[\\n\\t\\r]/g,\n\trspace = /\\s+/,\n\trreturn = /\\r/g,\n\trtype = /^(?:button|input)$/i,\n\trfocusable = /^(?:button|input|object|select|textarea)$/i,\n\trclickable = /^a(?:rea)?$/i,\n\trboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,\n\tgetSetAttribute = jQuery.support.getSetAttribute,\n\tnodeHook, boolHook, fixSpecified;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t});\n\t},\n\n\tprop: function( name, value ) {\n\t\treturn jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\tname = jQuery.propFix[ name ] || name;\n\t\treturn this.each(function() {\n\t\t\t// try/catch handles cases where IE balks (such as removing a property on window)\n\t\t\ttry {\n\t\t\t\tthis[ name ] = undefined;\n\t\t\t\tdelete this[ name ];\n\t\t\t} catch( e ) {}\n\t\t});\n\t},\n\n\taddClass: function( value ) {\n\t\tvar classNames, i, l, elem,\n\t\t\tsetClass, c, cl;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call(this, j, this.className) );\n\t\t\t});\n\t\t}\n\n\t\tif ( value && typeof value === \"string\" ) {\n\t\t\tclassNames = value.split( rspace );\n\n\t\t\tfor ( i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\telem = this[ i ];\n\n\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\tif ( !elem.className && classNames.length === 1 ) {\n\t\t\t\t\t\telem.className = value;\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsetClass = \" \" + elem.className + \" \";\n\n\t\t\t\t\t\tfor ( c = 0, cl = classNames.length; c < cl; c++ ) {\n\t\t\t\t\t\t\tif ( !~setClass.indexOf( \" \" + classNames[ c ] + \" \" ) ) {\n\t\t\t\t\t\t\t\tsetClass += classNames[ c ] + \" \";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telem.className = jQuery.trim( setClass );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classNames, i, l, elem, className, c, cl;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call(this, j, this.className) );\n\t\t\t});\n\t\t}\n\n\t\tif ( (value && typeof value === \"string\") || value === undefined ) {\n\t\t\tclassNames = ( value || \"\" ).split( rspace );\n\n\t\t\tfor ( i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\telem = this[ i ];\n\n\t\t\t\tif ( elem.nodeType === 1 && elem.className ) {\n\t\t\t\t\tif ( value ) {\n\t\t\t\t\t\tclassName = (\" \" + elem.className + \" \").replace( rclass, \" \" );\n\t\t\t\t\t\tfor ( c = 0, cl = classNames.length; c < cl; c++ ) {\n\t\t\t\t\t\t\tclassName = className.replace(\" \" + classNames[ c ] + \" \", \" \");\n\t\t\t\t\t\t}\n\t\t\t\t\t\telem.className = jQuery.trim( className );\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem.className = \"\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisBool = typeof stateVal === \"boolean\";\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( type === \"string\" ) {\n\t\t\t\t// toggle individual class names\n\t\t\t\tvar className,\n\t\t\t\t\ti = 0,\n\t\t\t\t\tself = jQuery( this ),\n\t\t\t\t\tstate = stateVal,\n\t\t\t\t\tclassNames = value.split( rspace );\n\n\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n\t\t\t\t\t// check each className given, space seperated list\n\t\t\t\t\tstate = isBool ? state : !self.hasClass( className );\n\t\t\t\t\tself[ state ? \"addClass\" : \"removeClass\" ]( className );\n\t\t\t\t}\n\n\t\t\t} else if ( type === \"undefined\" || type === \"boolean\" ) {\n\t\t\t\tif ( this.className ) {\n\t\t\t\t\t// store className if set\n\t\t\t\t\tjQuery._data( this, \"__className__\", this.className );\n\t\t\t\t}\n\n\t\t\t\t// toggle whole className\n\t\t\t\tthis.className = this.className || value === false ? \"\" : jQuery._data( this, \"__className__\" ) || \"\";\n\t\t\t}\n\t\t});\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className = \" \" + selector + \" \",\n\t\t\ti = 0,\n\t\t\tl = this.length;\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tif ( this[i].nodeType === 1 && (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) > -1 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t},\n\n\tval: function( value ) {\n\t\tvar hooks, ret, isFunction,\n\t\t\telem = this[0];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, \"value\" )) !== undefined ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\treturn typeof ret === \"string\" ?\n\t\t\t\t\t// handle most common string cases\n\t\t\t\t\tret.replace(rreturn, \"\") :\n\t\t\t\t\t// handle cases where value is null/undef or number\n\t\t\t\t\tret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each(function( i ) {\n\t\t\tvar self = jQuery(this), val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, self.val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\t\t\t} else if ( jQuery.isArray( val ) ) {\n\t\t\t\tval = jQuery.map(val, function ( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t});\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !(\"set\" in hooks) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\t\t\t\t// attributes.value is undefined in Blackberry 4.7 but\n\t\t\t\t// uses .value. See #6932\n\t\t\t\tvar val = elem.attributes.value;\n\t\t\t\treturn !val || val.specified ? elem.value : elem.text;\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, i, max, option,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tvalues = [],\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tone = elem.type === \"select-one\";\n\n\t\t\t\t// Nothing was selected\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\ti = one ? index : 0;\n\t\t\t\tmax = one ? index + 1 : options.length;\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\tif ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute(\"disabled\") === null) &&\n\t\t\t\t\t\t\t(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, \"optgroup\" )) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Fixes Bug #2551 -- select.val() broken in IE after form.reset()\n\t\t\t\tif ( one && !values.length && options.length ) {\n\t\t\t\t\treturn jQuery( options[ index ] ).val();\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar values = jQuery.makeArray( value );\n\n\t\t\t\tjQuery(elem).find(\"option\").each(function() {\n\t\t\t\t\tthis.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;\n\t\t\t\t});\n\n\t\t\t\tif ( !values.length ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t},\n\n\tattrFn: {\n\t\tval: true,\n\t\tcss: true,\n\t\thtml: true,\n\t\ttext: true,\n\t\tdata: true,\n\t\twidth: true,\n\t\theight: true,\n\t\toffset: true\n\t},\n\n\tattr: function( elem, name, value, pass ) {\n\t\tvar ret, hooks, notxml,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set attributes on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( pass && name in jQuery.attrFn ) {\n\t\t\treturn jQuery( elem )[ name ]( value );\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( notxml ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\n\t\t\t} else if ( hooks && \"set\" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\telem.setAttribute( name, \"\" + value );\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t} else if ( hooks && \"get\" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\treturn ret;\n\n\t\t} else {\n\n\t\t\tret = elem.getAttribute( name );\n\n\t\t\t// Non-existent attributes return null, we normalize to undefined\n\t\t\treturn ret === null ?\n\t\t\t\tundefined :\n\t\t\t\tret;\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar propName, attrNames, name, l, isBool,\n\t\t\ti = 0;\n\n\t\tif ( value && elem.nodeType === 1 ) {\n\t\t\tattrNames = value.toLowerCase().split( rspace );\n\t\t\tl = attrNames.length;\n\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tname = attrNames[ i ];\n\n\t\t\t\tif ( name ) {\n\t\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\t\t\t\t\tisBool = rboolean.test( name );\n\n\t\t\t\t\t// See #9699 for explanation of this approach (setting first, then removal)\n\t\t\t\t\t// Do not do this for boolean attributes (see #10870)\n\t\t\t\t\tif ( !isBool ) {\n\t\t\t\t\t\tjQuery.attr( elem, name, \"\" );\n\t\t\t\t\t}\n\t\t\t\t\telem.removeAttribute( getSetAttribute ? name : propName );\n\n\t\t\t\t\t// Set corresponding property to false for boolean attributes\n\t\t\t\t\tif ( isBool && propName in elem ) {\n\t\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\t// We can't allow the type property to be changed (since it causes problems in IE)\n\t\t\t\tif ( rtype.test( elem.nodeName ) && elem.parentNode ) {\n\t\t\t\t\tjQuery.error( \"type property can't be changed\" );\n\t\t\t\t} else if ( !jQuery.support.radioValue && value === \"radio\" && jQuery.nodeName(elem, \"input\") ) {\n\t\t\t\t\t// Setting the type on a radio button after the value resets the value in IE6-9\n\t\t\t\t\t// Reset value to it's default in case type is set after value\n\t\t\t\t\t// This is for element creation\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// Use the value property for back compat\n\t\t// Use the nodeHook for button elements in IE6/7 (#1954)\n\t\tvalue: {\n\t\t\tget: function( elem, name ) {\n\t\t\t\tif ( nodeHook && jQuery.nodeName( elem, \"button\" ) ) {\n\t\t\t\t\treturn nodeHook.get( elem, name );\n\t\t\t\t}\n\t\t\t\treturn name in elem ?\n\t\t\t\t\telem.value :\n\t\t\t\t\tnull;\n\t\t\t},\n\t\t\tset: function( elem, value, name ) {\n\t\t\t\tif ( nodeHook && jQuery.nodeName( elem, \"button\" ) ) {\n\t\t\t\t\treturn nodeHook.set( elem, value, name );\n\t\t\t\t}\n\t\t\t\t// Does not return so that setAttribute is also used\n\t\t\t\telem.value = value;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\ttabindex: \"tabIndex\",\n\t\treadonly: \"readOnly\",\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\",\n\t\tmaxlength: \"maxLength\",\n\t\tcellspacing: \"cellSpacing\",\n\t\tcellpadding: \"cellPadding\",\n\t\trowspan: \"rowSpan\",\n\t\tcolspan: \"colSpan\",\n\t\tusemap: \"useMap\",\n\t\tframeborder: \"frameBorder\",\n\t\tcontenteditable: \"contentEditable\"\n\t},\n\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks, notxml,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set properties on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\tif ( notxml ) {\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\treturn ( elem[ name ] = value );\n\t\t\t}\n\n\t\t} else {\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\treturn elem[ name ];\n\t\t\t}\n\t\t}\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\t\t\t\t// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set\n\t\t\t\t// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\tvar attributeNode = elem.getAttributeNode(\"tabindex\");\n\n\t\t\t\treturn attributeNode && attributeNode.specified ?\n\t\t\t\t\tparseInt( attributeNode.value, 10 ) :\n\t\t\t\t\trfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?\n\t\t\t\t\t\t0 :\n\t\t\t\t\t\tundefined;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)\njQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;\n\n// Hook for boolean attributes\nboolHook = {\n\tget: function( elem, name ) {\n\t\t// Align boolean attributes with corresponding properties\n\t\t// Fall back to attribute presence where some booleans are not supported\n\t\tvar attrNode,\n\t\t\tproperty = jQuery.prop( elem, name );\n\t\treturn property === true || typeof property !== \"boolean\" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?\n\t\t\tname.toLowerCase() :\n\t\t\tundefined;\n\t},\n\tset: function( elem, value, name ) {\n\t\tvar propName;\n\t\tif ( value === false ) {\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\t// value is true since we know at this point it's type boolean and not false\n\t\t\t// Set boolean attributes to the same name and set the DOM property\n\t\t\tpropName = jQuery.propFix[ name ] || name;\n\t\t\tif ( propName in elem ) {\n\t\t\t\t// Only set the IDL specifically if it already exists on the element\n\t\t\t\telem[ propName ] = true;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, name.toLowerCase() );\n\t\t}\n\t\treturn name;\n\t}\n};\n\n// IE6/7 do not support getting/setting some attributes with get/setAttribute\nif ( !getSetAttribute ) {\n\n\tfixSpecified = {\n\t\tname: true,\n\t\tid: true,\n\t\tcoords: true\n\t};\n\n\t// Use this for any attribute in IE6/7\n\t// This fixes almost every IE6/7 issue\n\tnodeHook = jQuery.valHooks.button = {\n\t\tget: function( elem, name ) {\n\t\t\tvar ret;\n\t\t\tret = elem.getAttributeNode( name );\n\t\t\treturn ret && ( fixSpecified[ name ] ? ret.nodeValue !== \"\" : ret.specified ) ?\n\t\t\t\tret.nodeValue :\n\t\t\t\tundefined;\n\t\t},\n\t\tset: function( elem, value, name ) {\n\t\t\t// Set the existing or create a new attribute node\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\tif ( !ret ) {\n\t\t\t\tret = document.createAttribute( name );\n\t\t\t\telem.setAttributeNode( ret );\n\t\t\t}\n\t\t\treturn ( ret.nodeValue = value + \"\" );\n\t\t}\n\t};\n\n\t// Apply the nodeHook to tabindex\n\tjQuery.attrHooks.tabindex.set = nodeHook.set;\n\n\t// Set width and height to auto instead of 0 on empty string( Bug #8150 )\n\t// This is for removals\n\tjQuery.each([ \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( value === \"\" ) {\n\t\t\t\t\telem.setAttribute( name, \"auto\" );\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n\n\t// Set contenteditable to false on removals(#10429)\n\t// Setting to empty string throws an error as an invalid value\n\tjQuery.attrHooks.contenteditable = {\n\t\tget: nodeHook.get,\n\t\tset: function( elem, value, name ) {\n\t\t\tif ( value === \"\" ) {\n\t\t\t\tvalue = \"false\";\n\t\t\t}\n\t\t\tnodeHook.set( elem, value, name );\n\t\t}\n\t};\n}\n\n\n// Some attributes require a special call on IE\nif ( !jQuery.support.hrefNormalized ) {\n\tjQuery.each([ \"href\", \"src\", \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar ret = elem.getAttribute( name, 2 );\n\t\t\t\treturn ret === null ? undefined : ret;\n\t\t\t}\n\t\t});\n\t});\n}\n\nif ( !jQuery.support.style ) {\n\tjQuery.attrHooks.style = {\n\t\tget: function( elem ) {\n\t\t\t// Return undefined in the case of empty string\n\t\t\t// Normalize to lowercase since IE uppercases css property names\n\t\t\treturn elem.style.cssText.toLowerCase() || undefined;\n\t\t},\n\t\tset: function( elem, value ) {\n\t\t\treturn ( elem.style.cssText = \"\" + value );\n\t\t}\n\t};\n}\n\n// Safari mis-reports the default selected property of an option\n// Accessing the parent's selectedIndex property fixes it\nif ( !jQuery.support.optSelected ) {\n\tjQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\t// Make sure that it also works with optgroups, see #5701\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t});\n}\n\n// IE6/7 call enctype encoding\nif ( !jQuery.support.enctype ) {\n\tjQuery.propFix.enctype = \"encoding\";\n}\n\n// Radios and checkboxes getter/setter\nif ( !jQuery.support.checkOn ) {\n\tjQuery.each([ \"radio\", \"checkbox\" ], function() {\n\t\tjQuery.valHooks[ this ] = {\n\t\t\tget: function( elem ) {\n\t\t\t\t// Handle the case where in Webkit \"\" is returned instead of \"on\" if a value isn't specified\n\t\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t\t}\n\t\t};\n\t});\n}\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {\n\t\tset: function( elem, value ) {\n\t\t\tif ( jQuery.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );\n\t\t\t}\n\t\t}\n\t});\n});\n\n\n\n\nvar rformElems = /^(?:textarea|input|select)$/i,\n\trtypenamespace = /^([^\\.]*)?(?:\\.(.+))?$/,\n\trhoverHack = /(?:^|\\s)hover(\\.\\S+)?\\b/,\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|contextmenu)|click/,\n\trfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\trquickIs = /^(\\w*)(?:#([\\w\\-]+))?(?:\\.([\\w\\-]+))?$/,\n\tquickParse = function( selector ) {\n\t\tvar quick = rquickIs.exec( selector );\n\t\tif ( quick ) {\n\t\t\t//   0  1    2   3\n\t\t\t// [ _, tag, id, class ]\n\t\t\tquick[1] = ( quick[1] || \"\" ).toLowerCase();\n\t\t\tquick[3] = quick[3] && new RegExp( \"(?:^|\\\\s)\" + quick[3] + \"(?:\\\\s|$)\" );\n\t\t}\n\t\treturn quick;\n\t},\n\tquickIs = function( elem, m ) {\n\t\tvar attrs = elem.attributes || {};\n\t\treturn (\n\t\t\t(!m[1] || elem.nodeName.toLowerCase() === m[1]) &&\n\t\t\t(!m[2] || (attrs.id || {}).value === m[2]) &&\n\t\t\t(!m[3] || m[3].test( (attrs[ \"class\" ] || {}).value ))\n\t\t);\n\t},\n\thoverHack = function( events ) {\n\t\treturn jQuery.event.special.hover ? events : events.replace( rhoverHack, \"mouseenter$1 mouseleave$1\" );\n\t};\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar elemData, eventHandle, events,\n\t\t\tt, tns, type, namespaces, handleObj,\n\t\t\thandleObjIn, quick, handlers, special;\n\n\t\t// Don't attach events to noData or text/comment nodes (allow plain objects tho)\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tevents = elemData.events;\n\t\tif ( !events ) {\n\t\t\telemData.events = events = {};\n\t\t}\n\t\teventHandle = elemData.handle;\n\t\tif ( !eventHandle ) {\n\t\t\telemData.handle = eventHandle = function( e ) {\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && (!e || jQuery.event.triggered !== e.type) ?\n\t\t\t\t\tjQuery.event.dispatch.apply( eventHandle.elem, arguments ) :\n\t\t\t\t\tundefined;\n\t\t\t};\n\t\t\t// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events\n\t\t\teventHandle.elem = elem;\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\t// jQuery(...).bind(\"mouseover mouseout\", fn);\n\t\ttypes = jQuery.trim( hoverHack(types) ).split( \" \" );\n\t\tfor ( t = 0; t < types.length; t++ ) {\n\n\t\t\ttns = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = tns[1];\n\t\t\tnamespaces = ( tns[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend({\n\t\t\t\ttype: type,\n\t\t\t\torigType: tns[1],\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tquick: selector && quickParse( selector ),\n\t\t\t\tnamespace: namespaces.join(\".\")\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\thandlers = events[ type ];\n\t\t\tif ( !handlers ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener/attachEvent if the special events handler returns false\n\t\t\t\tif ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\t\t\t\t\t// Bind the global event handler to the element\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle, false );\n\n\t\t\t\t\t} else if ( elem.attachEvent ) {\n\t\t\t\t\t\telem.attachEvent( \"on\" + type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t\t// Nullify elem to prevent memory leaks in IE\n\t\telem = null;\n\t},\n\n\tglobal: {},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar elemData = jQuery.hasData( elem ) && jQuery._data( elem ),\n\t\t\tt, tns, type, origType, namespaces, origCount,\n\t\t\tj, events, special, handle, eventType, handleObj;\n\n\t\tif ( !elemData || !(events = elemData.events) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = jQuery.trim( hoverHack( types || \"\" ) ).split(\" \");\n\t\tfor ( t = 0; t < types.length; t++ ) {\n\t\t\ttns = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tns[1];\n\t\t\tnamespaces = tns[2];\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector? special.delegateType : special.bindType ) || type;\n\t\t\teventType = events[ type ] || [];\n\t\t\torigCount = eventType.length;\n\t\t\tnamespaces = namespaces ? new RegExp(\"(^|\\\\.)\" + namespaces.split(\".\").sort().join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\") : null;\n\n\t\t\t// Remove matching events\n\t\t\tfor ( j = 0; j < eventType.length; j++ ) {\n\t\t\t\thandleObj = eventType[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t ( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t ( !namespaces || namespaces.test( handleObj.namespace ) ) &&\n\t\t\t\t\t ( !selector || selector === handleObj.selector || selector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\teventType.splice( j--, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\teventType.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( eventType.length === 0 && origCount !== eventType.length ) {\n\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\thandle = elemData.handle;\n\t\t\tif ( handle ) {\n\t\t\t\thandle.elem = null;\n\t\t\t}\n\n\t\t\t// removeData also checks for emptiness and clears the expando if empty\n\t\t\t// so use it instead of delete\n\t\t\tjQuery.removeData( elem, [ \"events\", \"handle\" ], true );\n\t\t}\n\t},\n\n\t// Events that are safe to short-circuit if no handlers are attached.\n\t// Native DOM events should not be added, they may have inline handlers.\n\tcustomEvent: {\n\t\t\"getData\": true,\n\t\t\"setData\": true,\n\t\t\"changeData\": true\n\t},\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Event object or event type\n\t\tvar type = event.type || event,\n\t\t\tnamespaces = [],\n\t\t\tcache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \"!\" ) >= 0 ) {\n\t\t\t// Exclusive events trigger only for the exact event (no namespaces)\n\t\t\ttype = type.slice(0, -1);\n\t\t\texclusive = true;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) >= 0 ) {\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split(\".\");\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\n\t\tif ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {\n\t\t\t// No jQuery handlers for this event type, and it can't have inline handlers\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an Event, Object, or just an event type string\n\t\tevent = typeof event === \"object\" ?\n\t\t\t// jQuery.Event object\n\t\t\tevent[ jQuery.expando ] ? event :\n\t\t\t// Object literal\n\t\t\tnew jQuery.Event( type, event ) :\n\t\t\t// Just the event type (string)\n\t\t\tnew jQuery.Event( type );\n\n\t\tevent.type = type;\n\t\tevent.isTrigger = true;\n\t\tevent.exclusive = exclusive;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.namespace_re = event.namespace? new RegExp(\"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\") : null;\n\t\tontype = type.indexOf( \":\" ) < 0 ? \"on\" + type : \"\";\n\n\t\t// Handle a global trigger\n\t\tif ( !elem ) {\n\n\t\t\t// TODO: Stop taunting the data cache; remove global events and always attach to document\n\t\t\tcache = jQuery.cache;\n\t\t\tfor ( i in cache ) {\n\t\t\t\tif ( cache[ i ].events && cache[ i ].events[ type ] ) {\n\t\t\t\t\tjQuery.event.trigger( event, data, cache[ i ].handle.elem, true );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data != null ? jQuery.makeArray( data ) : [];\n\t\tdata.unshift( event );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\teventPath = [[ elem, special.bindType || type ]];\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tcur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;\n\t\t\told = null;\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push([ cur, bubbleType ]);\n\t\t\t\told = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( old && old === elem.ownerDocument ) {\n\t\t\t\teventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\tfor ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {\n\n\t\t\tcur = eventPath[i][0];\n\t\t\tevent.type = eventPath[i][1];\n\n\t\t\thandle = ( jQuery._data( cur, \"events\" ) || {} )[ event.type ] && jQuery._data( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\t\t\t// Note that this is a bare JS function and not a jQuery handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&\n\t\t\t\t!(type === \"click\" && jQuery.nodeName( elem, \"a\" )) && jQuery.acceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name name as the event.\n\t\t\t\t// Can't use an .isFunction() check here because IE6/7 fails that test.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\t// IE<9 dies on focus/blur to hidden element (#1486)\n\t\t\t\tif ( ontype && elem[ type ] && ((type !== \"focus\" && type !== \"blur\") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\told = elem[ ontype ];\n\n\t\t\t\t\tif ( old ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\telem[ type ]();\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( old ) {\n\t\t\t\t\t\telem[ ontype ] = old;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\tdispatch: function( event ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tevent = jQuery.event.fix( event || window.event );\n\n\t\tvar handlers = ( (jQuery._data( this, \"events\" ) || {} )[ event.type ] || []),\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\targs = [].slice.call( arguments, 0 ),\n\t\t\trun_all = !event.exclusive && !event.namespace,\n\t\t\tspecial = jQuery.event.special[ event.type ] || {},\n\t\t\thandlerQueue = [],\n\t\t\ti, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[0] = event;\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers that should run if there are delegated events\n\t\t// Avoid non-left-click bubbling in Firefox (#3861)\n\t\tif ( delegateCount && !(event.button && event.type === \"click\") ) {\n\n\t\t\t// Pregenerate a single jQuery object for reuse with .is()\n\t\t\tjqcur = jQuery(this);\n\t\t\tjqcur.context = this.ownerDocument || this;\n\n\t\t\tfor ( cur = event.target; cur != this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't process events on disabled elements (#6911, #8165)\n\t\t\t\tif ( cur.disabled !== true ) {\n\t\t\t\t\tselMatch = {};\n\t\t\t\t\tmatches = [];\n\t\t\t\t\tjqcur[0] = cur;\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\t\t\t\t\t\tsel = handleObj.selector;\n\n\t\t\t\t\t\tif ( selMatch[ sel ] === undefined ) {\n\t\t\t\t\t\t\tselMatch[ sel ] = (\n\t\t\t\t\t\t\t\thandleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( selMatch[ sel ] ) {\n\t\t\t\t\t\t\tmatches.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matches.length ) {\n\t\t\t\t\t\thandlerQueue.push({ elem: cur, matches: matches });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tif ( handlers.length > delegateCount ) {\n\t\t\thandlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });\n\t\t}\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\tfor ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {\n\t\t\tmatched = handlerQueue[ i ];\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tfor ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {\n\t\t\t\thandleObj = matched.matches[ j ];\n\n\t\t\t\t// Triggered event must either 1) be non-exclusive and have no namespace, or\n\t\t\t\t// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.data = handleObj.data;\n\t\t\t\t\tevent.handleObj = handleObj;\n\n\t\t\t\t\tret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )\n\t\t\t\t\t\t\t.apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tevent.result = ret;\n\t\t\t\t\t\tif ( ret === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\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\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Includes some event props shared by KeyEvent and MouseEvent\n\t// *** attrChange attrName relatedNode srcElement  are not normalized, non-W3C, deprecated, will be removed in 1.8 ***\n\tprops: \"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),\n\n\tfixHooks: {},\n\n\tkeyHooks: {\n\t\tprops: \"char charCode key keyCode\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\n\t\t\t// Add which for key events\n\t\t\tif ( event.which == null ) {\n\t\t\t\tevent.which = original.charCode != null ? original.charCode : original.keyCode;\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tmouseHooks: {\n\t\tprops: \"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\t\t\tvar eventDoc, doc, body,\n\t\t\t\tbutton = original.button,\n\t\t\t\tfromElement = original.fromElement;\n\n\t\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\t\tif ( event.pageX == null && original.clientX != null ) {\n\t\t\t\teventDoc = event.target.ownerDocument || document;\n\t\t\t\tdoc = eventDoc.documentElement;\n\t\t\t\tbody = eventDoc.body;\n\n\t\t\t\tevent.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );\n\t\t\t\tevent.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );\n\t\t\t}\n\n\t\t\t// Add relatedTarget, if necessary\n\t\t\tif ( !event.relatedTarget && fromElement ) {\n\t\t\t\tevent.relatedTarget = fromElement === event.target ? original.toElement : fromElement;\n\t\t\t}\n\n\t\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t\t// Note: button is not normalized, so don't use it\n\t\t\tif ( !event.which && button !== undefined ) {\n\t\t\t\tevent.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// Create a writable copy of the event object and normalize some properties\n\t\tvar i, prop,\n\t\t\toriginalEvent = event,\n\t\t\tfixHook = jQuery.event.fixHooks[ event.type ] || {},\n\t\t\tcopy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n\t\tevent = jQuery.Event( originalEvent );\n\n\t\tfor ( i = copy.length; i; ) {\n\t\t\tprop = copy[ --i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)\n\t\tif ( !event.target ) {\n\t\t\tevent.target = originalEvent.srcElement || document;\n\t\t}\n\n\t\t// Target should not be a text node (#504, Safari)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\t// For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)\n\t\tif ( event.metaKey === undefined ) {\n\t\t\tevent.metaKey = event.ctrlKey;\n\t\t}\n\n\t\treturn fixHook.filter? fixHook.filter( event, originalEvent ) : event;\n\t},\n\n\tspecial: {\n\t\tready: {\n\t\t\t// Make sure the ready event is setup\n\t\t\tsetup: jQuery.bindReady\n\t\t},\n\n\t\tload: {\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\n\t\tfocus: {\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tsetup: function( data, namespaces, eventHandle ) {\n\t\t\t\t// We only want to do this special case on windows\n\t\t\t\tif ( jQuery.isWindow( this ) ) {\n\t\t\t\t\tthis.onbeforeunload = eventHandle;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tteardown: function( namespaces, eventHandle ) {\n\t\t\t\tif ( this.onbeforeunload === eventHandle ) {\n\t\t\t\t\tthis.onbeforeunload = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tsimulate: function( type, elem, event, bubble ) {\n\t\t// Piggyback on a donor event to simulate a different one.\n\t\t// Fake originalEvent to avoid donor's stopPropagation, but if the\n\t\t// simulated event prevents default then we do the same on the donor.\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{ type: type,\n\t\t\t\tisSimulated: true,\n\t\t\t\toriginalEvent: {}\n\t\t\t}\n\t\t);\n\t\tif ( bubble ) {\n\t\t\tjQuery.event.trigger( e, null, elem );\n\t\t} else {\n\t\t\tjQuery.event.dispatch.call( elem, e );\n\t\t}\n\t\tif ( e.isDefaultPrevented() ) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n};\n\n// Some plugins are using, but it's undocumented/deprecated and will be removed.\n// The 1.7 special event interface should provide all the hooks needed now.\njQuery.event.handle = jQuery.event.dispatch;\n\njQuery.removeEvent = document.removeEventListener ?\n\tfunction( elem, type, handle ) {\n\t\tif ( elem.removeEventListener ) {\n\t\t\telem.removeEventListener( type, handle, false );\n\t\t}\n\t} :\n\tfunction( elem, type, handle ) {\n\t\tif ( elem.detachEvent ) {\n\t\t\telem.detachEvent( \"on\" + type, handle );\n\t\t}\n\t};\n\njQuery.Event = function( src, props ) {\n\t// Allow instantiation without the 'new' keyword\n\tif ( !(this instanceof jQuery.Event) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||\n\t\t\tsrc.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\nfunction returnFalse() {\n\treturn false;\n}\nfunction returnTrue() {\n\treturn true;\n}\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tpreventDefault: function() {\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tvar e = this.originalEvent;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// if preventDefault exists run it on the original event\n\t\tif ( e.preventDefault ) {\n\t\t\te.preventDefault();\n\n\t\t// otherwise set the returnValue property of the original event to false (IE)\n\t\t} else {\n\t\t\te.returnValue = false;\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tvar e = this.originalEvent;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\t\t// if stopPropagation exists run it on the original event\n\t\tif ( e.stopPropagation ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t\t// otherwise set the cancelBubble property of the original event to true (IE)\n\t\te.cancelBubble = true;\n\t},\n\tstopImmediatePropagation: function() {\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\t\tthis.stopPropagation();\n\t},\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar target = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj,\n\t\t\t\tselector = handleObj.selector,\n\t\t\t\tret;\n\n\t\t\t// For mousenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || (related !== target && !jQuery.contains( target, related )) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n});\n\n// IE submit delegation\nif ( !jQuery.support.submitBubbles ) {\n\n\tjQuery.event.special.submit = {\n\t\tsetup: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Lazy-add a submit handler when a descendant form may potentially be submitted\n\t\t\tjQuery.event.add( this, \"click._submit keypress._submit\", function( e ) {\n\t\t\t\t// Node name check avoids a VML-related crash in IE (#9807)\n\t\t\t\tvar elem = e.target,\n\t\t\t\t\tform = jQuery.nodeName( elem, \"input\" ) || jQuery.nodeName( elem, \"button\" ) ? elem.form : undefined;\n\t\t\t\tif ( form && !form._submit_attached ) {\n\t\t\t\t\tjQuery.event.add( form, \"submit._submit\", function( event ) {\n\t\t\t\t\t\tevent._submit_bubble = true;\n\t\t\t\t\t});\n\t\t\t\t\tform._submit_attached = true;\n\t\t\t\t}\n\t\t\t});\n\t\t\t// return undefined since we don't need an event listener\n\t\t},\n\t\t\n\t\tpostDispatch: function( event ) {\n\t\t\t// If form was submitted by the user, bubble the event up the tree\n\t\t\tif ( event._submit_bubble ) {\n\t\t\t\tdelete event._submit_bubble;\n\t\t\t\tif ( this.parentNode && !event.isTrigger ) {\n\t\t\t\t\tjQuery.event.simulate( \"submit\", this.parentNode, event, true );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Remove delegated handlers; cleanData eventually reaps submit handlers attached above\n\t\t\tjQuery.event.remove( this, \"._submit\" );\n\t\t}\n\t};\n}\n\n// IE change delegation and checkbox/radio fix\nif ( !jQuery.support.changeBubbles ) {\n\n\tjQuery.event.special.change = {\n\n\t\tsetup: function() {\n\n\t\t\tif ( rformElems.test( this.nodeName ) ) {\n\t\t\t\t// IE doesn't fire change on a check/radio until blur; trigger it on click\n\t\t\t\t// after a propertychange. Eat the blur-change in special.change.handle.\n\t\t\t\t// This still fires onchange a second time for check/radio after blur.\n\t\t\t\tif ( this.type === \"checkbox\" || this.type === \"radio\" ) {\n\t\t\t\t\tjQuery.event.add( this, \"propertychange._change\", function( event ) {\n\t\t\t\t\t\tif ( event.originalEvent.propertyName === \"checked\" ) {\n\t\t\t\t\t\t\tthis._just_changed = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tjQuery.event.add( this, \"click._change\", function( event ) {\n\t\t\t\t\t\tif ( this._just_changed && !event.isTrigger ) {\n\t\t\t\t\t\t\tthis._just_changed = false;\n\t\t\t\t\t\t\tjQuery.event.simulate( \"change\", this, event, true );\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// Delegated event; lazy-add a change handler on descendant inputs\n\t\t\tjQuery.event.add( this, \"beforeactivate._change\", function( e ) {\n\t\t\t\tvar elem = e.target;\n\n\t\t\t\tif ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {\n\t\t\t\t\tjQuery.event.add( elem, \"change._change\", function( event ) {\n\t\t\t\t\t\tif ( this.parentNode && !event.isSimulated && !event.isTrigger ) {\n\t\t\t\t\t\t\tjQuery.event.simulate( \"change\", this.parentNode, event, true );\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\telem._change_attached = true;\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\thandle: function( event ) {\n\t\t\tvar elem = event.target;\n\n\t\t\t// Swallow native change events from checkbox/radio, we already triggered them above\n\t\t\tif ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== \"radio\" && elem.type !== \"checkbox\") ) {\n\t\t\t\treturn event.handleObj.handler.apply( this, arguments );\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\tjQuery.event.remove( this, \"._change\" );\n\n\t\t\treturn rformElems.test( this.nodeName );\n\t\t}\n\t};\n}\n\n// Create \"bubbling\" focus and blur events\nif ( !jQuery.support.focusinBubbles ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler while someone wants focusin/focusout\n\t\tvar attaches = 0,\n\t\t\thandler = function( event ) {\n\t\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );\n\t\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tif ( attaches++ === 0 ) {\n\t\t\t\t\tdocument.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tif ( --attaches === 0 ) {\n\t\t\t\t\tdocument.removeEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t});\n}\n\njQuery.fn.extend({\n\n\ton: function( types, selector, data, fn, /*INTERNAL*/ one ) {\n\t\tvar origFn, type;\n\n\t\t// Types can be a map of types/handlers\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-Object, selector, data )\n\t\t\tif ( typeof selector !== \"string\" ) { // && selector != null\n\t\t\t\t// ( types-Object, data )\n\t\t\t\tdata = data || selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.on( type, selector, data, types[ type ], one );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( data == null && fn == null ) {\n\t\t\t// ( types, fn )\n\t\t\tfn = selector;\n\t\t\tdata = selector = undefined;\n\t\t} else if ( fn == null ) {\n\t\t\tif ( typeof selector === \"string\" ) {\n\t\t\t\t// ( types, selector, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = undefined;\n\t\t\t} else {\n\t\t\t\t// ( types, data, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t} else if ( !fn ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( one === 1 ) {\n\t\t\torigFn = fn;\n\t\t\tfn = function( event ) {\n\t\t\t\t// Can use an empty set, since event contains the info\n\t\t\t\tjQuery().off( event );\n\t\t\t\treturn origFn.apply( this, arguments );\n\t\t\t};\n\t\t\t// Use same guid so caller can remove using origFn\n\t\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.add( this, types, fn, data, selector );\n\t\t});\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn this.on( types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\tvar handleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ? handleObj.origType + \".\" + handleObj.namespace : handleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( var type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t});\n\t},\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tlive: function( types, data, fn ) {\n\t\tjQuery( this.context ).on( types, this.selector, data, fn );\n\t\treturn this;\n\t},\n\tdie: function( types, fn ) {\n\t\tjQuery( this.context ).off( types, this.selector || \"**\", fn );\n\t\treturn this;\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length == 1? this.off( selector, \"**\" ) : this.off( types, selector, fn );\n\t},\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t});\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tif ( this[0] ) {\n\t\t\treturn jQuery.event.trigger( type, data, this[0], true );\n\t\t}\n\t},\n\n\ttoggle: function( fn ) {\n\t\t// Save reference to arguments for access in closure\n\t\tvar args = arguments,\n\t\t\tguid = fn.guid || jQuery.guid++,\n\t\t\ti = 0,\n\t\t\ttoggler = function( event ) {\n\t\t\t\t// Figure out which function to execute\n\t\t\t\tvar lastToggle = ( jQuery._data( this, \"lastToggle\" + fn.guid ) || 0 ) % i;\n\t\t\t\tjQuery._data( this, \"lastToggle\" + fn.guid, lastToggle + 1 );\n\n\t\t\t\t// Make sure that clicks stop\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\t// and execute the function\n\t\t\t\treturn args[ lastToggle ].apply( this, arguments ) || false;\n\t\t\t};\n\n\t\t// link all the functions, so any of them can unbind this click handler\n\t\ttoggler.guid = guid;\n\t\twhile ( i < args.length ) {\n\t\t\targs[ i++ ].guid = guid;\n\t\t}\n\n\t\treturn this.click( toggler );\n\t},\n\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n});\n\njQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error contextmenu\").split(\" \"), function( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\tif ( fn == null ) {\n\t\t\tfn = data;\n\t\t\tdata = null;\n\t\t}\n\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n\n\tif ( jQuery.attrFn ) {\n\t\tjQuery.attrFn[ name ] = true;\n\t}\n\n\tif ( rkeyEvent.test( name ) ) {\n\t\tjQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;\n\t}\n\n\tif ( rmouseEvent.test( name ) ) {\n\t\tjQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;\n\t}\n});\n\n\n\n/*!\n * Sizzle CSS Selector Engine\n *  Copyright 2011, The Dojo Foundation\n *  Released under the MIT, BSD, and GPL Licenses.\n *  More information: http://sizzlejs.com/\n */\n(function(){\n\nvar chunker = /((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,\n\texpando = \"sizcache\" + (Math.random() + '').replace('.', ''),\n\tdone = 0,\n\ttoString = Object.prototype.toString,\n\thasDuplicate = false,\n\tbaseHasDuplicate = true,\n\trBackslash = /\\\\/g,\n\trNonWord = /\\W/;\n\n// Here we check if the JavaScript engine is using some sort of\n// optimization where it does not always call our comparision\n// function. If that is the case, discard the hasDuplicate value.\n//   Thus far that includes Google Chrome.\n[0, 0].sort(function() {\n\tbaseHasDuplicate = false;\n\treturn 0;\n});\n\nvar Sizzle = function( selector, context, results, seed ) {\n\tresults = results || [];\n\tcontext = context || document;\n\n\tvar origContext = context;\n\n\tif ( context.nodeType !== 1 && context.nodeType !== 9 ) {\n\t\treturn [];\n\t}\n\n\tif ( !selector || typeof selector !== \"string\" ) {\n\t\treturn results;\n\t}\n\n\tvar m, set, checkSet, extra, ret, cur, pop, i,\n\t\tprune = true,\n\t\tcontextXML = Sizzle.isXML( context ),\n\t\tparts = [],\n\t\tsoFar = selector;\n\n\t// Reset the position of the chunker regexp (start from head)\n\tdo {\n\t\tchunker.exec( \"\" );\n\t\tm = chunker.exec( soFar );\n\n\t\tif ( m ) {\n\t\t\tsoFar = m[3];\n\n\t\t\tparts.push( m[1] );\n\n\t\t\tif ( m[2] ) {\n\t\t\t\textra = m[3];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} while ( m );\n\n\tif ( parts.length > 1 && origPOS.exec( selector ) ) {\n\n\t\tif ( parts.length === 2 && Expr.relative[ parts[0] ] ) {\n\t\t\tset = posProcess( parts[0] + parts[1], context, seed );\n\n\t\t} else {\n\t\t\tset = Expr.relative[ parts[0] ] ?\n\t\t\t\t[ context ] :\n\t\t\t\tSizzle( parts.shift(), context );\n\n\t\t\twhile ( parts.length ) {\n\t\t\t\tselector = parts.shift();\n\n\t\t\t\tif ( Expr.relative[ selector ] ) {\n\t\t\t\t\tselector += parts.shift();\n\t\t\t\t}\n\n\t\t\t\tset = posProcess( selector, set, seed );\n\t\t\t}\n\t\t}\n\n\t} else {\n\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\t// (but not if it'll be faster if the inner selector is an ID)\n\t\tif ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&\n\t\t\t\tExpr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {\n\n\t\t\tret = Sizzle.find( parts.shift(), context, contextXML );\n\t\t\tcontext = ret.expr ?\n\t\t\t\tSizzle.filter( ret.expr, ret.set )[0] :\n\t\t\t\tret.set[0];\n\t\t}\n\n\t\tif ( context ) {\n\t\t\tret = seed ?\n\t\t\t\t{ expr: parts.pop(), set: makeArray(seed) } :\n\t\t\t\tSizzle.find( parts.pop(), parts.length === 1 && (parts[0] === \"~\" || parts[0] === \"+\") && context.parentNode ? context.parentNode : context, contextXML );\n\n\t\t\tset = ret.expr ?\n\t\t\t\tSizzle.filter( ret.expr, ret.set ) :\n\t\t\t\tret.set;\n\n\t\t\tif ( parts.length > 0 ) {\n\t\t\t\tcheckSet = makeArray( set );\n\n\t\t\t} else {\n\t\t\t\tprune = false;\n\t\t\t}\n\n\t\t\twhile ( parts.length ) {\n\t\t\t\tcur = parts.pop();\n\t\t\t\tpop = cur;\n\n\t\t\t\tif ( !Expr.relative[ cur ] ) {\n\t\t\t\t\tcur = \"\";\n\t\t\t\t} else {\n\t\t\t\t\tpop = parts.pop();\n\t\t\t\t}\n\n\t\t\t\tif ( pop == null ) {\n\t\t\t\t\tpop = context;\n\t\t\t\t}\n\n\t\t\t\tExpr.relative[ cur ]( checkSet, pop, contextXML );\n\t\t\t}\n\n\t\t} else {\n\t\t\tcheckSet = parts = [];\n\t\t}\n\t}\n\n\tif ( !checkSet ) {\n\t\tcheckSet = set;\n\t}\n\n\tif ( !checkSet ) {\n\t\tSizzle.error( cur || selector );\n\t}\n\n\tif ( toString.call(checkSet) === \"[object Array]\" ) {\n\t\tif ( !prune ) {\n\t\t\tresults.push.apply( results, checkSet );\n\n\t\t} else if ( context && context.nodeType === 1 ) {\n\t\t\tfor ( i = 0; checkSet[i] != null; i++ ) {\n\t\t\t\tif ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {\n\t\t\t\t\tresults.push( set[i] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\t\t\tfor ( i = 0; checkSet[i] != null; i++ ) {\n\t\t\t\tif ( checkSet[i] && checkSet[i].nodeType === 1 ) {\n\t\t\t\t\tresults.push( set[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t} else {\n\t\tmakeArray( checkSet, results );\n\t}\n\n\tif ( extra ) {\n\t\tSizzle( extra, origContext, results, seed );\n\t\tSizzle.uniqueSort( results );\n\t}\n\n\treturn results;\n};\n\nSizzle.uniqueSort = function( results ) {\n\tif ( sortOrder ) {\n\t\thasDuplicate = baseHasDuplicate;\n\t\tresults.sort( sortOrder );\n\n\t\tif ( hasDuplicate ) {\n\t\t\tfor ( var i = 1; i < results.length; i++ ) {\n\t\t\t\tif ( results[i] === results[ i - 1 ] ) {\n\t\t\t\t\tresults.splice( i--, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n};\n\nSizzle.matches = function( expr, set ) {\n\treturn Sizzle( expr, null, null, set );\n};\n\nSizzle.matchesSelector = function( node, expr ) {\n\treturn Sizzle( expr, null, null, [node] ).length > 0;\n};\n\nSizzle.find = function( expr, context, isXML ) {\n\tvar set, i, len, match, type, left;\n\n\tif ( !expr ) {\n\t\treturn [];\n\t}\n\n\tfor ( i = 0, len = Expr.order.length; i < len; i++ ) {\n\t\ttype = Expr.order[i];\n\n\t\tif ( (match = Expr.leftMatch[ type ].exec( expr )) ) {\n\t\t\tleft = match[1];\n\t\t\tmatch.splice( 1, 1 );\n\n\t\t\tif ( left.substr( left.length - 1 ) !== \"\\\\\" ) {\n\t\t\t\tmatch[1] = (match[1] || \"\").replace( rBackslash, \"\" );\n\t\t\t\tset = Expr.find[ type ]( match, context, isXML );\n\n\t\t\t\tif ( set != null ) {\n\t\t\t\t\texpr = expr.replace( Expr.match[ type ], \"\" );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( !set ) {\n\t\tset = typeof context.getElementsByTagName !== \"undefined\" ?\n\t\t\tcontext.getElementsByTagName( \"*\" ) :\n\t\t\t[];\n\t}\n\n\treturn { set: set, expr: expr };\n};\n\nSizzle.filter = function( expr, set, inplace, not ) {\n\tvar match, anyFound,\n\t\ttype, found, item, filter, left,\n\t\ti, pass,\n\t\told = expr,\n\t\tresult = [],\n\t\tcurLoop = set,\n\t\tisXMLFilter = set && set[0] && Sizzle.isXML( set[0] );\n\n\twhile ( expr && set.length ) {\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {\n\t\t\t\tfilter = Expr.filter[ type ];\n\t\t\t\tleft = match[1];\n\n\t\t\t\tanyFound = false;\n\n\t\t\t\tmatch.splice(1,1);\n\n\t\t\t\tif ( left.substr( left.length - 1 ) === \"\\\\\" ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif ( curLoop === result ) {\n\t\t\t\t\tresult = [];\n\t\t\t\t}\n\n\t\t\t\tif ( Expr.preFilter[ type ] ) {\n\t\t\t\t\tmatch = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );\n\n\t\t\t\t\tif ( !match ) {\n\t\t\t\t\t\tanyFound = found = true;\n\n\t\t\t\t\t} else if ( match === true ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\tfor ( i = 0; (item = curLoop[i]) != null; i++ ) {\n\t\t\t\t\t\tif ( item ) {\n\t\t\t\t\t\t\tfound = filter( item, match, i, curLoop );\n\t\t\t\t\t\t\tpass = not ^ found;\n\n\t\t\t\t\t\t\tif ( inplace && found != null ) {\n\t\t\t\t\t\t\t\tif ( pass ) {\n\t\t\t\t\t\t\t\t\tanyFound = true;\n\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcurLoop[i] = false;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else if ( pass ) {\n\t\t\t\t\t\t\t\tresult.push( item );\n\t\t\t\t\t\t\t\tanyFound = true;\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\n\t\t\t\tif ( found !== undefined ) {\n\t\t\t\t\tif ( !inplace ) {\n\t\t\t\t\t\tcurLoop = result;\n\t\t\t\t\t}\n\n\t\t\t\t\texpr = expr.replace( Expr.match[ type ], \"\" );\n\n\t\t\t\t\tif ( !anyFound ) {\n\t\t\t\t\t\treturn [];\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Improper expression\n\t\tif ( expr === old ) {\n\t\t\tif ( anyFound == null ) {\n\t\t\t\tSizzle.error( expr );\n\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\told = expr;\n\t}\n\n\treturn curLoop;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Utility function for retreiving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\nvar getText = Sizzle.getText = function( elem ) {\n    var i, node,\n\t\tnodeType = elem.nodeType,\n\t\tret = \"\";\n\n\tif ( nodeType ) {\n\t\tif ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t\t// Use textContent for elements\n\t\t\t// innerText usage removed for consistency of new lines (see #11153)\n\t\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\t\treturn elem.textContent;\n\t\t\t} else {\n\t\t\t\t// Traverse it's children\n\t\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\t\tret += getText( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\t\treturn elem.nodeValue;\n\t\t}\n\t} else {\n\n\t\t// If no nodeType, this is expected to be an array\n\t\tfor ( i = 0; (node = elem[i]); i++ ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tif ( node.nodeType !== 8 ) {\n\t\t\t\tret += getText( node );\n\t\t\t}\n\t\t}\n\t}\n\treturn ret;\n};\n\nvar Expr = Sizzle.selectors = {\n\torder: [ \"ID\", \"NAME\", \"TAG\" ],\n\n\tmatch: {\n\t\tID: /#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,\n\t\tCLASS: /\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,\n\t\tNAME: /\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,\n\t\tATTR: /\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(?:(['\"])(.*?)\\3|(#?(?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)*)|)|)\\s*\\]/,\n\t\tTAG: /^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,\n\t\tCHILD: /:(only|nth|last|first)-child(?:\\(\\s*(even|odd|(?:[+\\-]?\\d+|(?:[+\\-]?\\d*)?n\\s*(?:[+\\-]\\s*\\d+)?))\\s*\\))?/,\n\t\tPOS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,\n\t\tPSEUDO: /:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/\n\t},\n\n\tleftMatch: {},\n\n\tattrMap: {\n\t\t\"class\": \"className\",\n\t\t\"for\": \"htmlFor\"\n\t},\n\n\tattrHandle: {\n\t\thref: function( elem ) {\n\t\t\treturn elem.getAttribute( \"href\" );\n\t\t},\n\t\ttype: function( elem ) {\n\t\t\treturn elem.getAttribute( \"type\" );\n\t\t}\n\t},\n\n\trelative: {\n\t\t\"+\": function(checkSet, part){\n\t\t\tvar isPartStr = typeof part === \"string\",\n\t\t\t\tisTag = isPartStr && !rNonWord.test( part ),\n\t\t\t\tisPartStrNotTag = isPartStr && !isTag;\n\n\t\t\tif ( isTag ) {\n\t\t\t\tpart = part.toLowerCase();\n\t\t\t}\n\n\t\t\tfor ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {\n\t\t\t\tif ( (elem = checkSet[i]) ) {\n\t\t\t\t\twhile ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}\n\n\t\t\t\t\tcheckSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?\n\t\t\t\t\t\telem || false :\n\t\t\t\t\t\telem === part;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( isPartStrNotTag ) {\n\t\t\t\tSizzle.filter( part, checkSet, true );\n\t\t\t}\n\t\t},\n\n\t\t\">\": function( checkSet, part ) {\n\t\t\tvar elem,\n\t\t\t\tisPartStr = typeof part === \"string\",\n\t\t\t\ti = 0,\n\t\t\t\tl = checkSet.length;\n\n\t\t\tif ( isPartStr && !rNonWord.test( part ) ) {\n\t\t\t\tpart = part.toLowerCase();\n\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\telem = checkSet[i];\n\n\t\t\t\t\tif ( elem ) {\n\t\t\t\t\t\tvar parent = elem.parentNode;\n\t\t\t\t\t\tcheckSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\telem = checkSet[i];\n\n\t\t\t\t\tif ( elem ) {\n\t\t\t\t\t\tcheckSet[i] = isPartStr ?\n\t\t\t\t\t\t\telem.parentNode :\n\t\t\t\t\t\t\telem.parentNode === part;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( isPartStr ) {\n\t\t\t\t\tSizzle.filter( part, checkSet, true );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t\"\": function(checkSet, part, isXML){\n\t\t\tvar nodeCheck,\n\t\t\t\tdoneName = done++,\n\t\t\t\tcheckFn = dirCheck;\n\n\t\t\tif ( typeof part === \"string\" && !rNonWord.test( part ) ) {\n\t\t\t\tpart = part.toLowerCase();\n\t\t\t\tnodeCheck = part;\n\t\t\t\tcheckFn = dirNodeCheck;\n\t\t\t}\n\n\t\t\tcheckFn( \"parentNode\", part, doneName, checkSet, nodeCheck, isXML );\n\t\t},\n\n\t\t\"~\": function( checkSet, part, isXML ) {\n\t\t\tvar nodeCheck,\n\t\t\t\tdoneName = done++,\n\t\t\t\tcheckFn = dirCheck;\n\n\t\t\tif ( typeof part === \"string\" && !rNonWord.test( part ) ) {\n\t\t\t\tpart = part.toLowerCase();\n\t\t\t\tnodeCheck = part;\n\t\t\t\tcheckFn = dirNodeCheck;\n\t\t\t}\n\n\t\t\tcheckFn( \"previousSibling\", part, doneName, checkSet, nodeCheck, isXML );\n\t\t}\n\t},\n\n\tfind: {\n\t\tID: function( match, context, isXML ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n\t\t\t\tvar m = context.getElementById(match[1]);\n\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\treturn m && m.parentNode ? [m] : [];\n\t\t\t}\n\t\t},\n\n\t\tNAME: function( match, context ) {\n\t\t\tif ( typeof context.getElementsByName !== \"undefined\" ) {\n\t\t\t\tvar ret = [],\n\t\t\t\t\tresults = context.getElementsByName( match[1] );\n\n\t\t\t\tfor ( var i = 0, l = results.length; i < l; i++ ) {\n\t\t\t\t\tif ( results[i].getAttribute(\"name\") === match[1] ) {\n\t\t\t\t\t\tret.push( results[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn ret.length === 0 ? null : ret;\n\t\t\t}\n\t\t},\n\n\t\tTAG: function( match, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( match[1] );\n\t\t\t}\n\t\t}\n\t},\n\tpreFilter: {\n\t\tCLASS: function( match, curLoop, inplace, result, not, isXML ) {\n\t\t\tmatch = \" \" + match[1].replace( rBackslash, \"\" ) + \" \";\n\n\t\t\tif ( isXML ) {\n\t\t\t\treturn match;\n\t\t\t}\n\n\t\t\tfor ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {\n\t\t\t\tif ( elem ) {\n\t\t\t\t\tif ( not ^ (elem.className && (\" \" + elem.className + \" \").replace(/[\\t\\n\\r]/g, \" \").indexOf(match) >= 0) ) {\n\t\t\t\t\t\tif ( !inplace ) {\n\t\t\t\t\t\t\tresult.push( elem );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if ( inplace ) {\n\t\t\t\t\t\tcurLoop[i] = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\n\t\tID: function( match ) {\n\t\t\treturn match[1].replace( rBackslash, \"\" );\n\t\t},\n\n\t\tTAG: function( match, curLoop ) {\n\t\t\treturn match[1].replace( rBackslash, \"\" ).toLowerCase();\n\t\t},\n\n\t\tCHILD: function( match ) {\n\t\t\tif ( match[1] === \"nth\" ) {\n\t\t\t\tif ( !match[2] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\tmatch[2] = match[2].replace(/^\\+|\\s*/g, '');\n\n\t\t\t\t// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'\n\t\t\t\tvar test = /(-?)(\\d*)(?:n([+\\-]?\\d*))?/.exec(\n\t\t\t\t\tmatch[2] === \"even\" && \"2n\" || match[2] === \"odd\" && \"2n+1\" ||\n\t\t\t\t\t!/\\D/.test( match[2] ) && \"0n+\" + match[2] || match[2]);\n\n\t\t\t\t// calculate the numbers (first)n+(last) including if they are negative\n\t\t\t\tmatch[2] = (test[1] + (test[2] || 1)) - 0;\n\t\t\t\tmatch[3] = test[3] - 0;\n\t\t\t}\n\t\t\telse if ( match[2] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\t// TODO: Move to normal caching system\n\t\t\tmatch[0] = done++;\n\n\t\t\treturn match;\n\t\t},\n\n\t\tATTR: function( match, curLoop, inplace, result, not, isXML ) {\n\t\t\tvar name = match[1] = match[1].replace( rBackslash, \"\" );\n\n\t\t\tif ( !isXML && Expr.attrMap[name] ) {\n\t\t\t\tmatch[1] = Expr.attrMap[name];\n\t\t\t}\n\n\t\t\t// Handle if an un-quoted value was used\n\t\t\tmatch[4] = ( match[4] || match[5] || \"\" ).replace( rBackslash, \"\" );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[4] = \" \" + match[4] + \" \";\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\tPSEUDO: function( match, curLoop, inplace, result, not ) {\n\t\t\tif ( match[1] === \"not\" ) {\n\t\t\t\t// If we're dealing with a complex expression, or a simple one\n\t\t\t\tif ( ( chunker.exec(match[3]) || \"\" ).length > 1 || /^\\w/.test(match[3]) ) {\n\t\t\t\t\tmatch[3] = Sizzle(match[3], null, null, curLoop);\n\n\t\t\t\t} else {\n\t\t\t\t\tvar ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);\n\n\t\t\t\t\tif ( !inplace ) {\n\t\t\t\t\t\tresult.push.apply( result, ret );\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\tPOS: function( match ) {\n\t\t\tmatch.unshift( true );\n\n\t\t\treturn match;\n\t\t}\n\t},\n\n\tfilters: {\n\t\tenabled: function( elem ) {\n\t\t\treturn elem.disabled === false && elem.type !== \"hidden\";\n\t\t},\n\n\t\tdisabled: function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\tchecked: function( elem ) {\n\t\t\treturn elem.checked === true;\n\t\t},\n\n\t\tselected: function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\tparent: function( elem ) {\n\t\t\treturn !!elem.firstChild;\n\t\t},\n\n\t\tempty: function( elem ) {\n\t\t\treturn !elem.firstChild;\n\t\t},\n\n\t\thas: function( elem, i, match ) {\n\t\t\treturn !!Sizzle( match[3], elem ).length;\n\t\t},\n\n\t\theader: function( elem ) {\n\t\t\treturn (/h\\d/i).test( elem.nodeName );\n\t\t},\n\n\t\ttext: function( elem ) {\n\t\t\tvar attr = elem.getAttribute( \"type\" ), type = elem.type;\n\t\t\t// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)\n\t\t\t// use getAttribute instead to test this case\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"text\" === type && ( attr === type || attr === null );\n\t\t},\n\n\t\tradio: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"radio\" === elem.type;\n\t\t},\n\n\t\tcheckbox: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"checkbox\" === elem.type;\n\t\t},\n\n\t\tfile: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"file\" === elem.type;\n\t\t},\n\n\t\tpassword: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"password\" === elem.type;\n\t\t},\n\n\t\tsubmit: function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn (name === \"input\" || name === \"button\") && \"submit\" === elem.type;\n\t\t},\n\n\t\timage: function( elem ) {\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" && \"image\" === elem.type;\n\t\t},\n\n\t\treset: function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn (name === \"input\" || name === \"button\") && \"reset\" === elem.type;\n\t\t},\n\n\t\tbutton: function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && \"button\" === elem.type || name === \"button\";\n\t\t},\n\n\t\tinput: function( elem ) {\n\t\t\treturn (/input|select|textarea|button/i).test( elem.nodeName );\n\t\t},\n\n\t\tfocus: function( elem ) {\n\t\t\treturn elem === elem.ownerDocument.activeElement;\n\t\t}\n\t},\n\tsetFilters: {\n\t\tfirst: function( elem, i ) {\n\t\t\treturn i === 0;\n\t\t},\n\n\t\tlast: function( elem, i, match, array ) {\n\t\t\treturn i === array.length - 1;\n\t\t},\n\n\t\teven: function( elem, i ) {\n\t\t\treturn i % 2 === 0;\n\t\t},\n\n\t\todd: function( elem, i ) {\n\t\t\treturn i % 2 === 1;\n\t\t},\n\n\t\tlt: function( elem, i, match ) {\n\t\t\treturn i < match[3] - 0;\n\t\t},\n\n\t\tgt: function( elem, i, match ) {\n\t\t\treturn i > match[3] - 0;\n\t\t},\n\n\t\tnth: function( elem, i, match ) {\n\t\t\treturn match[3] - 0 === i;\n\t\t},\n\n\t\teq: function( elem, i, match ) {\n\t\t\treturn match[3] - 0 === i;\n\t\t}\n\t},\n\tfilter: {\n\t\tPSEUDO: function( elem, match, i, array ) {\n\t\t\tvar name = match[1],\n\t\t\t\tfilter = Expr.filters[ name ];\n\n\t\t\tif ( filter ) {\n\t\t\t\treturn filter( elem, i, match, array );\n\n\t\t\t} else if ( name === \"contains\" ) {\n\t\t\t\treturn (elem.textContent || elem.innerText || getText([ elem ]) || \"\").indexOf(match[3]) >= 0;\n\n\t\t\t} else if ( name === \"not\" ) {\n\t\t\t\tvar not = match[3];\n\n\t\t\t\tfor ( var j = 0, l = not.length; j < l; j++ ) {\n\t\t\t\t\tif ( not[j] === elem ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\n\t\t\t} else {\n\t\t\t\tSizzle.error( name );\n\t\t\t}\n\t\t},\n\n\t\tCHILD: function( elem, match ) {\n\t\t\tvar first, last,\n\t\t\t\tdoneName, parent, cache,\n\t\t\t\tcount, diff,\n\t\t\t\ttype = match[1],\n\t\t\t\tnode = elem;\n\n\t\t\tswitch ( type ) {\n\t\t\t\tcase \"only\":\n\t\t\t\tcase \"first\":\n\t\t\t\t\twhile ( (node = node.previousSibling) ) {\n\t\t\t\t\t\tif ( node.nodeType === 1 ) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( type === \"first\" ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\tnode = elem;\n\n\t\t\t\t\t/* falls through */\n\t\t\t\tcase \"last\":\n\t\t\t\t\twhile ( (node = node.nextSibling) ) {\n\t\t\t\t\t\tif ( node.nodeType === 1 ) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\n\t\t\t\tcase \"nth\":\n\t\t\t\t\tfirst = match[2];\n\t\t\t\t\tlast = match[3];\n\n\t\t\t\t\tif ( first === 1 && last === 0 ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\tdoneName = match[0];\n\t\t\t\t\tparent = elem.parentNode;\n\n\t\t\t\t\tif ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {\n\t\t\t\t\t\tcount = 0;\n\n\t\t\t\t\t\tfor ( node = parent.firstChild; node; node = node.nextSibling ) {\n\t\t\t\t\t\t\tif ( node.nodeType === 1 ) {\n\t\t\t\t\t\t\t\tnode.nodeIndex = ++count;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tparent[ expando ] = doneName;\n\t\t\t\t\t}\n\n\t\t\t\t\tdiff = elem.nodeIndex - last;\n\n\t\t\t\t\tif ( first === 0 ) {\n\t\t\t\t\t\treturn diff === 0;\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tID: function( elem, match ) {\n\t\t\treturn elem.nodeType === 1 && elem.getAttribute(\"id\") === match;\n\t\t},\n\n\t\tTAG: function( elem, match ) {\n\t\t\treturn (match === \"*\" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;\n\t\t},\n\n\t\tCLASS: function( elem, match ) {\n\t\t\treturn (\" \" + (elem.className || elem.getAttribute(\"class\")) + \" \")\n\t\t\t\t.indexOf( match ) > -1;\n\t\t},\n\n\t\tATTR: function( elem, match ) {\n\t\t\tvar name = match[1],\n\t\t\t\tresult = Sizzle.attr ?\n\t\t\t\t\tSizzle.attr( elem, name ) :\n\t\t\t\t\tExpr.attrHandle[ name ] ?\n\t\t\t\t\tExpr.attrHandle[ name ]( elem ) :\n\t\t\t\t\telem[ name ] != null ?\n\t\t\t\t\t\telem[ name ] :\n\t\t\t\t\t\telem.getAttribute( name ),\n\t\t\t\tvalue = result + \"\",\n\t\t\t\ttype = match[2],\n\t\t\t\tcheck = match[4];\n\n\t\t\treturn result == null ?\n\t\t\t\ttype === \"!=\" :\n\t\t\t\t!type && Sizzle.attr ?\n\t\t\t\tresult != null :\n\t\t\t\ttype === \"=\" ?\n\t\t\t\tvalue === check :\n\t\t\t\ttype === \"*=\" ?\n\t\t\t\tvalue.indexOf(check) >= 0 :\n\t\t\t\ttype === \"~=\" ?\n\t\t\t\t(\" \" + value + \" \").indexOf(check) >= 0 :\n\t\t\t\t!check ?\n\t\t\t\tvalue && result !== false :\n\t\t\t\ttype === \"!=\" ?\n\t\t\t\tvalue !== check :\n\t\t\t\ttype === \"^=\" ?\n\t\t\t\tvalue.indexOf(check) === 0 :\n\t\t\t\ttype === \"$=\" ?\n\t\t\t\tvalue.substr(value.length - check.length) === check :\n\t\t\t\ttype === \"|=\" ?\n\t\t\t\tvalue === check || value.substr(0, check.length + 1) === check + \"-\" :\n\t\t\t\tfalse;\n\t\t},\n\n\t\tPOS: function( elem, match, i, array ) {\n\t\t\tvar name = match[2],\n\t\t\t\tfilter = Expr.setFilters[ name ];\n\n\t\t\tif ( filter ) {\n\t\t\t\treturn filter( elem, i, match, array );\n\t\t\t}\n\t\t}\n\t}\n};\n\nvar origPOS = Expr.match.POS,\n\tfescape = function(all, num){\n\t\treturn \"\\\\\" + (num - 0 + 1);\n\t};\n\nfor ( var type in Expr.match ) {\n\tExpr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\\[]*\\])(?![^\\(]*\\))/.source) );\n\tExpr.leftMatch[ type ] = new RegExp( /(^(?:.|\\r|\\n)*?)/.source + Expr.match[ type ].source.replace(/\\\\(\\d+)/g, fescape) );\n}\n// Expose origPOS\n// \"global\" as in regardless of relation to brackets/parens\nExpr.match.globalPOS = origPOS;\n\nvar makeArray = function( array, results ) {\n\tarray = Array.prototype.slice.call( array, 0 );\n\n\tif ( results ) {\n\t\tresults.push.apply( results, array );\n\t\treturn results;\n\t}\n\n\treturn array;\n};\n\n// Perform a simple check to determine if the browser is capable of\n// converting a NodeList to an array using builtin methods.\n// Also verifies that the returned array holds DOM nodes\n// (which is not the case in the Blackberry browser)\ntry {\n\tArray.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;\n\n// Provide a fallback method if it does not work\n} catch( e ) {\n\tmakeArray = function( array, results ) {\n\t\tvar i = 0,\n\t\t\tret = results || [];\n\n\t\tif ( toString.call(array) === \"[object Array]\" ) {\n\t\t\tArray.prototype.push.apply( ret, array );\n\n\t\t} else {\n\t\t\tif ( typeof array.length === \"number\" ) {\n\t\t\t\tfor ( var l = array.length; i < l; i++ ) {\n\t\t\t\t\tret.push( array[i] );\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tfor ( ; array[i]; i++ ) {\n\t\t\t\t\tret.push( array[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t};\n}\n\nvar sortOrder, siblingCheck;\n\nif ( document.documentElement.compareDocumentPosition ) {\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tif ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {\n\t\t\treturn a.compareDocumentPosition ? -1 : 1;\n\t\t}\n\n\t\treturn a.compareDocumentPosition(b) & 4 ? -1 : 1;\n\t};\n\n} else {\n\tsortOrder = function( a, b ) {\n\t\t// The nodes are identical, we can exit early\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\n\t\t// Fallback to using sourceIndex (in IE) if it's available on both nodes\n\t\t} else if ( a.sourceIndex && b.sourceIndex ) {\n\t\t\treturn a.sourceIndex - b.sourceIndex;\n\t\t}\n\n\t\tvar al, bl,\n\t\t\tap = [],\n\t\t\tbp = [],\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tcur = aup;\n\n\t\t// If the nodes are siblings (or identical) we can do a quick check\n\t\tif ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\n\t\t// If no parents were found then the nodes are disconnected\n\t\t} else if ( !aup ) {\n\t\t\treturn -1;\n\n\t\t} else if ( !bup ) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Otherwise they're somewhere else in the tree so we need\n\t\t// to build up a full list of the parentNodes for comparison\n\t\twhile ( cur ) {\n\t\t\tap.unshift( cur );\n\t\t\tcur = cur.parentNode;\n\t\t}\n\n\t\tcur = bup;\n\n\t\twhile ( cur ) {\n\t\t\tbp.unshift( cur );\n\t\t\tcur = cur.parentNode;\n\t\t}\n\n\t\tal = ap.length;\n\t\tbl = bp.length;\n\n\t\t// Start walking down the tree looking for a discrepancy\n\t\tfor ( var i = 0; i < al && i < bl; i++ ) {\n\t\t\tif ( ap[i] !== bp[i] ) {\n\t\t\t\treturn siblingCheck( ap[i], bp[i] );\n\t\t\t}\n\t\t}\n\n\t\t// We ended someplace up the tree so do a sibling check\n\t\treturn i === al ?\n\t\t\tsiblingCheck( a, bp[i], -1 ) :\n\t\t\tsiblingCheck( ap[i], b, 1 );\n\t};\n\n\tsiblingCheck = function( a, b, ret ) {\n\t\tif ( a === b ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tvar cur = a.nextSibling;\n\n\t\twhile ( cur ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tcur = cur.nextSibling;\n\t\t}\n\n\t\treturn 1;\n\t};\n}\n\n// Check to see if the browser returns elements by name when\n// querying by getElementById (and provide a workaround)\n(function(){\n\t// We're going to inject a fake input element with a specified name\n\tvar form = document.createElement(\"div\"),\n\t\tid = \"script\" + (new Date()).getTime(),\n\t\troot = document.documentElement;\n\n\tform.innerHTML = \"<a name='\" + id + \"'/>\";\n\n\t// Inject it into the root element, check its status, and remove it quickly\n\troot.insertBefore( form, root.firstChild );\n\n\t// The workaround has to do additional checks after a getElementById\n\t// Which slows things down for other browsers (hence the branching)\n\tif ( document.getElementById( id ) ) {\n\t\tExpr.find.ID = function( match, context, isXML ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n\t\t\t\tvar m = context.getElementById(match[1]);\n\n\t\t\t\treturn m ?\n\t\t\t\t\tm.id === match[1] || typeof m.getAttributeNode !== \"undefined\" && m.getAttributeNode(\"id\").nodeValue === match[1] ?\n\t\t\t\t\t\t[m] :\n\t\t\t\t\t\tundefined :\n\t\t\t\t\t[];\n\t\t\t}\n\t\t};\n\n\t\tExpr.filter.ID = function( elem, match ) {\n\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" && elem.getAttributeNode(\"id\");\n\n\t\t\treturn elem.nodeType === 1 && node && node.nodeValue === match;\n\t\t};\n\t}\n\n\troot.removeChild( form );\n\n\t// release memory in IE\n\troot = form = null;\n})();\n\n(function(){\n\t// Check to see if the browser returns only elements\n\t// when doing getElementsByTagName(\"*\")\n\n\t// Create a fake element\n\tvar div = document.createElement(\"div\");\n\tdiv.appendChild( document.createComment(\"\") );\n\n\t// Make sure no comments are found\n\tif ( div.getElementsByTagName(\"*\").length > 0 ) {\n\t\tExpr.find.TAG = function( match, context ) {\n\t\t\tvar results = context.getElementsByTagName( match[1] );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( match[1] === \"*\" ) {\n\t\t\t\tvar tmp = [];\n\n\t\t\t\tfor ( var i = 0; results[i]; i++ ) {\n\t\t\t\t\tif ( results[i].nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( results[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresults = tmp;\n\t\t\t}\n\n\t\t\treturn results;\n\t\t};\n\t}\n\n\t// Check to see if an attribute returns normalized href attributes\n\tdiv.innerHTML = \"<a href='#'></a>\";\n\n\tif ( div.firstChild && typeof div.firstChild.getAttribute !== \"undefined\" &&\n\t\t\tdiv.firstChild.getAttribute(\"href\") !== \"#\" ) {\n\n\t\tExpr.attrHandle.href = function( elem ) {\n\t\t\treturn elem.getAttribute( \"href\", 2 );\n\t\t};\n\t}\n\n\t// release memory in IE\n\tdiv = null;\n})();\n\nif ( document.querySelectorAll ) {\n\t(function(){\n\t\tvar oldSizzle = Sizzle,\n\t\t\tdiv = document.createElement(\"div\"),\n\t\t\tid = \"__sizzle__\";\n\n\t\tdiv.innerHTML = \"<p class='TEST'></p>\";\n\n\t\t// Safari can't handle uppercase or unicode characters when\n\t\t// in quirks mode.\n\t\tif ( div.querySelectorAll && div.querySelectorAll(\".TEST\").length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tSizzle = function( query, context, extra, seed ) {\n\t\t\tcontext = context || document;\n\n\t\t\t// Only use querySelectorAll on non-XML documents\n\t\t\t// (ID selectors don't work in non-HTML documents)\n\t\t\tif ( !seed && !Sizzle.isXML(context) ) {\n\t\t\t\t// See if we find a selector to speed up\n\t\t\t\tvar match = /^(\\w+$)|^\\.([\\w\\-]+$)|^#([\\w\\-]+$)/.exec( query );\n\n\t\t\t\tif ( match && (context.nodeType === 1 || context.nodeType === 9) ) {\n\t\t\t\t\t// Speed-up: Sizzle(\"TAG\")\n\t\t\t\t\tif ( match[1] ) {\n\t\t\t\t\t\treturn makeArray( context.getElementsByTagName( query ), extra );\n\n\t\t\t\t\t// Speed-up: Sizzle(\".CLASS\")\n\t\t\t\t\t} else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {\n\t\t\t\t\t\treturn makeArray( context.getElementsByClassName( match[2] ), extra );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( context.nodeType === 9 ) {\n\t\t\t\t\t// Speed-up: Sizzle(\"body\")\n\t\t\t\t\t// The body element only exists once, optimize finding it\n\t\t\t\t\tif ( query === \"body\" && context.body ) {\n\t\t\t\t\t\treturn makeArray( [ context.body ], extra );\n\n\t\t\t\t\t// Speed-up: Sizzle(\"#ID\")\n\t\t\t\t\t} else if ( match && match[3] ) {\n\t\t\t\t\t\tvar elem = context.getElementById( match[3] );\n\n\t\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t\t// Handle the case where IE and Opera return items\n\t\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === match[3] ) {\n\t\t\t\t\t\t\t\treturn makeArray( [ elem ], extra );\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn makeArray( [], extra );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn makeArray( context.querySelectorAll(query), extra );\n\t\t\t\t\t} catch(qsaError) {}\n\n\t\t\t\t// qSA works strangely on Element-rooted queries\n\t\t\t\t// We can work around this by specifying an extra ID on the root\n\t\t\t\t// and working up from there (Thanks to Andrew Dupont for the technique)\n\t\t\t\t// IE 8 doesn't work on object elements\n\t\t\t\t} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n\t\t\t\t\tvar oldContext = context,\n\t\t\t\t\t\told = context.getAttribute( \"id\" ),\n\t\t\t\t\t\tnid = old || id,\n\t\t\t\t\t\thasParent = context.parentNode,\n\t\t\t\t\t\trelativeHierarchySelector = /^\\s*[+~]/.test( query );\n\n\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\tcontext.setAttribute( \"id\", nid );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnid = nid.replace( /'/g, \"\\\\$&\" );\n\t\t\t\t\t}\n\t\t\t\t\tif ( relativeHierarchySelector && hasParent ) {\n\t\t\t\t\t\tcontext = context.parentNode;\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif ( !relativeHierarchySelector || hasParent ) {\n\t\t\t\t\t\t\treturn makeArray( context.querySelectorAll( \"[id='\" + nid + \"'] \" + query ), extra );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} catch(pseudoError) {\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\t\toldContext.removeAttribute( \"id\" );\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\treturn oldSizzle(query, context, extra, seed);\n\t\t};\n\n\t\tfor ( var prop in oldSizzle ) {\n\t\t\tSizzle[ prop ] = oldSizzle[ prop ];\n\t\t}\n\n\t\t// release memory in IE\n\t\tdiv = null;\n\t})();\n}\n\n(function(){\n\tvar html = document.documentElement,\n\t\tmatches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;\n\n\tif ( matches ) {\n\t\t// Check to see if it's possible to do matchesSelector\n\t\t// on a disconnected node (IE 9 fails this)\n\t\tvar disconnectedMatch = !matches.call( document.createElement( \"div\" ), \"div\" ),\n\t\t\tpseudoWorks = false;\n\n\t\ttry {\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( document.documentElement, \"[test!='']:sizzle\" );\n\n\t\t} catch( pseudoError ) {\n\t\t\tpseudoWorks = true;\n\t\t}\n\n\t\tSizzle.matchesSelector = function( node, expr ) {\n\t\t\t// Make sure that attribute selectors are quoted\n\t\t\texpr = expr.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g, \"='$1']\");\n\n\t\t\tif ( !Sizzle.isXML( node ) ) {\n\t\t\t\ttry {\n\t\t\t\t\tif ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {\n\t\t\t\t\t\tvar ret = matches.call( node, expr );\n\n\t\t\t\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\t\t\t\tif ( ret || !disconnectedMatch ||\n\t\t\t\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t\t\t\t// fragment in IE 9, so check for that\n\t\t\t\t\t\t\t\tnode.document && node.document.nodeType !== 11 ) {\n\t\t\t\t\t\t\treturn ret;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t\treturn Sizzle(expr, null, null, [node]).length > 0;\n\t\t};\n\t}\n})();\n\n(function(){\n\tvar div = document.createElement(\"div\");\n\n\tdiv.innerHTML = \"<div class='test e'></div><div class='test'></div>\";\n\n\t// Opera can't find a second classname (in 9.6)\n\t// Also, make sure that getElementsByClassName actually exists\n\tif ( !div.getElementsByClassName || div.getElementsByClassName(\"e\").length === 0 ) {\n\t\treturn;\n\t}\n\n\t// Safari caches class attributes, doesn't catch changes (in 3.2)\n\tdiv.lastChild.className = \"e\";\n\n\tif ( div.getElementsByClassName(\"e\").length === 1 ) {\n\t\treturn;\n\t}\n\n\tExpr.order.splice(1, 0, \"CLASS\");\n\tExpr.find.CLASS = function( match, context, isXML ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && !isXML ) {\n\t\t\treturn context.getElementsByClassName(match[1]);\n\t\t}\n\t};\n\n\t// release memory in IE\n\tdiv = null;\n})();\n\nfunction dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n\t\tvar elem = checkSet[i];\n\n\t\tif ( elem ) {\n\t\t\tvar match = false;\n\n\t\t\telem = elem[dir];\n\n\t\t\twhile ( elem ) {\n\t\t\t\tif ( elem[ expando ] === doneName ) {\n\t\t\t\t\tmatch = checkSet[elem.sizset];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( elem.nodeType === 1 && !isXML ){\n\t\t\t\t\telem[ expando ] = doneName;\n\t\t\t\t\telem.sizset = i;\n\t\t\t\t}\n\n\t\t\t\tif ( elem.nodeName.toLowerCase() === cur ) {\n\t\t\t\t\tmatch = elem;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\telem = elem[dir];\n\t\t\t}\n\n\t\t\tcheckSet[i] = match;\n\t\t}\n\t}\n}\n\nfunction dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n\t\tvar elem = checkSet[i];\n\n\t\tif ( elem ) {\n\t\t\tvar match = false;\n\n\t\t\telem = elem[dir];\n\n\t\t\twhile ( elem ) {\n\t\t\t\tif ( elem[ expando ] === doneName ) {\n\t\t\t\t\tmatch = checkSet[elem.sizset];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\tif ( !isXML ) {\n\t\t\t\t\t\telem[ expando ] = doneName;\n\t\t\t\t\t\telem.sizset = i;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( typeof cur !== \"string\" ) {\n\t\t\t\t\t\tif ( elem === cur ) {\n\t\t\t\t\t\t\tmatch = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {\n\t\t\t\t\t\tmatch = elem;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telem = elem[dir];\n\t\t\t}\n\n\t\t\tcheckSet[i] = match;\n\t\t}\n\t}\n}\n\nif ( document.documentElement.contains ) {\n\tSizzle.contains = function( a, b ) {\n\t\treturn a !== b && (a.contains ? a.contains(b) : true);\n\t};\n\n} else if ( document.documentElement.compareDocumentPosition ) {\n\tSizzle.contains = function( a, b ) {\n\t\treturn !!(a.compareDocumentPosition(b) & 16);\n\t};\n\n} else {\n\tSizzle.contains = function() {\n\t\treturn false;\n\t};\n}\n\nSizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;\n\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\nvar posProcess = function( selector, context, seed ) {\n\tvar match,\n\t\ttmpSet = [],\n\t\tlater = \"\",\n\t\troot = context.nodeType ? [context] : context;\n\n\t// Position selectors must be done after the filter\n\t// And so must :not(positional) so we move all PSEUDOs to the end\n\twhile ( (match = Expr.match.PSEUDO.exec( selector )) ) {\n\t\tlater += match[0];\n\t\tselector = selector.replace( Expr.match.PSEUDO, \"\" );\n\t}\n\n\tselector = Expr.relative[selector] ? selector + \"*\" : selector;\n\n\tfor ( var i = 0, l = root.length; i < l; i++ ) {\n\t\tSizzle( selector, root[i], tmpSet, seed );\n\t}\n\n\treturn Sizzle.filter( later, tmpSet );\n};\n\n// EXPOSE\n// Override sizzle attribute retrieval\nSizzle.attr = jQuery.attr;\nSizzle.selectors.attrMap = {};\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.filters;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n})();\n\n\nvar runtil = /Until$/,\n\trparentsprev = /^(?:parents|prevUntil|prevAll)/,\n\t// Note: This RegExp should be improved, or likely pulled from Sizzle\n\trmultiselector = /,/,\n\tisSimple = /^.[^:#\\[\\.,]*$/,\n\tslice = Array.prototype.slice,\n\tPOS = jQuery.expr.match.globalPOS,\n\t// methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend({\n\tfind: function( selector ) {\n\t\tvar self = this,\n\t\t\ti, l;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn jQuery( selector ).filter(function() {\n\t\t\t\tfor ( i = 0, l = self.length; i < l; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tvar ret = this.pushStack( \"\", \"find\", selector ),\n\t\t\tlength, n, r;\n\n\t\tfor ( i = 0, l = this.length; i < l; i++ ) {\n\t\t\tlength = ret.length;\n\t\t\tjQuery.find( selector, this[i], ret );\n\n\t\t\tif ( i > 0 ) {\n\t\t\t\t// Make sure that the results are unique\n\t\t\t\tfor ( n = length; n < ret.length; n++ ) {\n\t\t\t\t\tfor ( r = 0; r < length; r++ ) {\n\t\t\t\t\t\tif ( ret[r] === ret[n] ) {\n\t\t\t\t\t\t\tret.splice(n--, 1);\n\t\t\t\t\t\t\tbreak;\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 ret;\n\t},\n\n\thas: function( target ) {\n\t\tvar targets = jQuery( target );\n\t\treturn this.filter(function() {\n\t\t\tfor ( var i = 0, l = targets.length; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[i] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, false), \"not\", selector);\n\t},\n\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, true), \"filter\", selector );\n\t},\n\n\tis: function( selector ) {\n\t\treturn !!selector && (\n\t\t\ttypeof selector === \"string\" ?\n\t\t\t\t// If this is a positional selector, check membership in the returned set\n\t\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\t\tPOS.test( selector ) ?\n\t\t\t\t\tjQuery( selector, this.context ).index( this[0] ) >= 0 :\n\t\t\t\t\tjQuery.filter( selector, this ).length > 0 :\n\t\t\t\tthis.filter( selector ).length > 0 );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar ret = [], i, l, cur = this[0];\n\n\t\t// Array (deprecated as of jQuery 1.7)\n\t\tif ( jQuery.isArray( selectors ) ) {\n\t\t\tvar level = 1;\n\n\t\t\twhile ( cur && cur.ownerDocument && cur !== context ) {\n\t\t\t\tfor ( i = 0; i < selectors.length; i++ ) {\n\n\t\t\t\t\tif ( jQuery( cur ).is( selectors[ i ] ) ) {\n\t\t\t\t\t\tret.push({ selector: selectors[ i ], elem: cur, level: level });\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcur = cur.parentNode;\n\t\t\t\tlevel++;\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\t\t// String\n\t\tvar pos = POS.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( i = 0, l = this.length; i < l; i++ ) {\n\t\t\tcur = this[i];\n\n\t\t\twhile ( cur ) {\n\t\t\t\tif ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {\n\t\t\t\t\tret.push( cur );\n\t\t\t\t\tbreak;\n\n\t\t\t\t} else {\n\t\t\t\t\tcur = cur.parentNode;\n\t\t\t\t\tif ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tret = ret.length > 1 ? jQuery.unique( ret ) : ret;\n\n\t\treturn this.pushStack( ret, \"closest\", selectors );\n\t},\n\n\t// Determine the position of an element within\n\t// the matched set of elements\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;\n\t\t}\n\n\t\t// index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn jQuery.inArray( this[0], jQuery( elem ) );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn jQuery.inArray(\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[0] : elem, this );\n\t},\n\n\tadd: function( selector, context ) {\n\t\tvar set = typeof selector === \"string\" ?\n\t\t\t\tjQuery( selector, context ) :\n\t\t\t\tjQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),\n\t\t\tall = jQuery.merge( this.get(), set );\n\n\t\treturn this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?\n\t\t\tall :\n\t\t\tjQuery.unique( all ) );\n\t},\n\n\tandSelf: function() {\n\t\treturn this.add( this.prevObject );\n\t}\n});\n\n// A painfully simple check to see if an element is disconnected\n// from a document (should be improved, where feasible).\nfunction isDisconnected( node ) {\n\treturn !node || !node.parentNode || node.parentNode.nodeType === 11;\n}\n\njQuery.each({\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn jQuery.dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn jQuery.nth( elem, 2, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn jQuery.nth( elem, 2, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn jQuery.sibling( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn jQuery.nodeName( elem, \"iframe\" ) ?\n\t\t\telem.contentDocument || elem.contentWindow.document :\n\t\t\tjQuery.makeArray( elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar ret = jQuery.map( this, fn, until );\n\n\t\tif ( !runtil.test( name ) ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tret = jQuery.filter( selector, ret );\n\t\t}\n\n\t\tret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;\n\n\t\tif ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {\n\t\t\tret = ret.reverse();\n\t\t}\n\n\t\treturn this.pushStack( ret, name, slice.call( arguments ).join(\",\") );\n\t};\n});\n\njQuery.extend({\n\tfilter: function( expr, elems, not ) {\n\t\tif ( not ) {\n\t\t\texpr = \":not(\" + expr + \")\";\n\t\t}\n\n\t\treturn elems.length === 1 ?\n\t\t\tjQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :\n\t\t\tjQuery.find.matches(expr, elems);\n\t},\n\n\tdir: function( elem, dir, until ) {\n\t\tvar matched = [],\n\t\t\tcur = elem[ dir ];\n\n\t\twhile ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {\n\t\t\tif ( cur.nodeType === 1 ) {\n\t\t\t\tmatched.push( cur );\n\t\t\t}\n\t\t\tcur = cur[dir];\n\t\t}\n\t\treturn matched;\n\t},\n\n\tnth: function( cur, result, dir, elem ) {\n\t\tresult = result || 1;\n\t\tvar num = 0;\n\n\t\tfor ( ; cur; cur = cur[dir] ) {\n\t\t\tif ( cur.nodeType === 1 && ++num === result ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn cur;\n\t},\n\n\tsibling: function( n, elem ) {\n\t\tvar r = [];\n\n\t\tfor ( ; n; n = n.nextSibling ) {\n\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\t\tr.push( n );\n\t\t\t}\n\t\t}\n\n\t\treturn r;\n\t}\n});\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, keep ) {\n\n\t// Can't pass null or undefined to indexOf in Firefox 4\n\t// Set to 0 to skip string check\n\tqualifier = qualifier || 0;\n\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep(elements, function( elem, i ) {\n\t\t\tvar retVal = !!qualifier.call( elem, i, elem );\n\t\t\treturn retVal === keep;\n\t\t});\n\n\t} else if ( qualifier.nodeType ) {\n\t\treturn jQuery.grep(elements, function( elem, i ) {\n\t\t\treturn ( elem === qualifier ) === keep;\n\t\t});\n\n\t} else if ( typeof qualifier === \"string\" ) {\n\t\tvar filtered = jQuery.grep(elements, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t});\n\n\t\tif ( isSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter(qualifier, filtered, !keep);\n\t\t} else {\n\t\t\tqualifier = jQuery.filter( qualifier, filtered );\n\t\t}\n\t}\n\n\treturn jQuery.grep(elements, function( elem, i ) {\n\t\treturn ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;\n\t});\n}\n\n\n\n\nfunction createSafeFragment( document ) {\n\tvar list = nodeNames.split( \"|\" ),\n\tsafeFrag = document.createDocumentFragment();\n\n\tif ( safeFrag.createElement ) {\n\t\twhile ( list.length ) {\n\t\t\tsafeFrag.createElement(\n\t\t\t\tlist.pop()\n\t\t\t);\n\t\t}\n\t}\n\treturn safeFrag;\n}\n\nvar nodeNames = \"abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|\" +\n\t\t\"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",\n\trinlinejQuery = / jQuery\\d+=\"(?:\\d+|null)\"/g,\n\trleadingWhitespace = /^\\s+/,\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,\n\trtagName = /<([\\w:]+)/,\n\trtbody = /<tbody/i,\n\trhtml = /<|&#?\\w+;/,\n\trnoInnerhtml = /<(?:script|style)/i,\n\trnocache = /<(?:script|object|embed|option|style)/i,\n\trnoshimcache = new RegExp(\"<(?:\" + nodeNames + \")[\\\\s/>]\", \"i\"),\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptType = /\\/(java|ecma)script/i,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|\\-\\-)/,\n\twrapMap = {\n\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\t\tlegend: [ 1, \"<fieldset>\", \"</fieldset>\" ],\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\t\tcol: [ 2, \"<table><tbody></tbody><colgroup>\", \"</colgroup></table>\" ],\n\t\tarea: [ 1, \"<map>\", \"</map>\" ],\n\t\t_default: [ 0, \"\", \"\" ]\n\t},\n\tsafeFragment = createSafeFragment( document );\n\nwrapMap.optgroup = wrapMap.option;\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// IE can't serialize <link> and <script> tags normally\nif ( !jQuery.support.htmlSerialize ) {\n\twrapMap._default = [ 1, \"div<div>\", \"</div>\" ];\n}\n\njQuery.fn.extend({\n\ttext: function( value ) {\n\t\treturn jQuery.access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );\n\t\t}, null, value, arguments.length );\n\t},\n\n\twrapAll: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapAll( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[0] ) {\n\t\t\t// The elements to wrap the target around\n\t\t\tvar wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);\n\n\t\t\tif ( this[0].parentNode ) {\n\t\t\t\twrap.insertBefore( this[0] );\n\t\t\t}\n\n\t\t\twrap.map(function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstChild && elem.firstChild.nodeType === 1 ) {\n\t\t\t\t\telem = elem.firstChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t}).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapInner( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t});\n\t},\n\n\twrap: function( html ) {\n\t\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each(function(i) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );\n\t\t});\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each(function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t}).end();\n\t},\n\n\tappend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 ) {\n\t\t\t\tthis.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 ) {\n\t\t\t\tthis.insertBefore( elem, this.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\tif ( this[0] && this[0].parentNode ) {\n\t\t\treturn this.domManip(arguments, false, function( elem ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t});\n\t\t} else if ( arguments.length ) {\n\t\t\tvar set = jQuery.clean( arguments );\n\t\t\tset.push.apply( set, this.toArray() );\n\t\t\treturn this.pushStack( set, \"before\", arguments );\n\t\t}\n\t},\n\n\tafter: function() {\n\t\tif ( this[0] && this[0].parentNode ) {\n\t\t\treturn this.domManip(arguments, false, function( elem ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t});\n\t\t} else if ( arguments.length ) {\n\t\t\tvar set = this.pushStack( this, \"after\", arguments );\n\t\t\tset.push.apply( set, jQuery.clean(arguments) );\n\t\t\treturn set;\n\t\t}\n\t},\n\n\t// keepData is for internal use only--do not document\n\tremove: function( selector, keepData ) {\n\t\tfor ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n\t\t\tif ( !selector || jQuery.filter( selector, [ elem ] ).length ) {\n\t\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n\t\t\t\t\tjQuery.cleanData( elem.getElementsByTagName(\"*\") );\n\t\t\t\t\tjQuery.cleanData( [ elem ] );\n\t\t\t\t}\n\n\t\t\t\tif ( elem.parentNode ) {\n\t\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tempty: function() {\n\t\tfor ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( elem.getElementsByTagName(\"*\") );\n\t\t\t}\n\n\t\t\t// Remove any remaining nodes\n\t\t\twhile ( elem.firstChild ) {\n\t\t\t\telem.removeChild( elem.firstChild );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function () {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t});\n\t},\n\n\thtml: function( value ) {\n\t\treturn jQuery.access( this, function( value ) {\n\t\t\tvar elem = this[0] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined ) {\n\t\t\t\treturn elem.nodeType === 1 ?\n\t\t\t\t\telem.innerHTML.replace( rinlinejQuery, \"\" ) :\n\t\t\t\t\tnull;\n\t\t\t}\n\n\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [\"\", \"\"] )[1].toLowerCase() ] ) {\n\n\t\t\t\tvalue = value.replace( rxhtmlTag, \"<$1></$2>\" );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor (; i < l; i++ ) {\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\telem = this[i] || {};\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( elem.getElementsByTagName( \"*\" ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function( value ) {\n\t\tif ( this[0] && this[0].parentNode ) {\n\t\t\t// Make sure that the elements are removed from the DOM before they are inserted\n\t\t\t// this can help fix replacing a parent with child elements\n\t\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\t\treturn this.each(function(i) {\n\t\t\t\t\tvar self = jQuery(this), old = self.html();\n\t\t\t\t\tself.replaceWith( value.call( this, i, old ) );\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif ( typeof value !== \"string\" ) {\n\t\t\t\tvalue = jQuery( value ).detach();\n\t\t\t}\n\n\t\t\treturn this.each(function() {\n\t\t\t\tvar next = this.nextSibling,\n\t\t\t\t\tparent = this.parentNode;\n\n\t\t\t\tjQuery( this ).remove();\n\n\t\t\t\tif ( next ) {\n\t\t\t\t\tjQuery(next).before( value );\n\t\t\t\t} else {\n\t\t\t\t\tjQuery(parent).append( value );\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\treturn this.length ?\n\t\t\t\tthis.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), \"replaceWith\", value ) :\n\t\t\t\tthis;\n\t\t}\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, table, callback ) {\n\t\tvar results, first, fragment, parent,\n\t\t\tvalue = args[0],\n\t\t\tscripts = [];\n\n\t\t// We can't cloneNode fragments that contain checked, in WebKit\n\t\tif ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === \"string\" && rchecked.test( value ) ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tjQuery(this).domManip( args, table, callback, true );\n\t\t\t});\n\t\t}\n\n\t\tif ( jQuery.isFunction(value) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\targs[0] = value.call(this, i, table ? self.html() : undefined);\n\t\t\t\tself.domManip( args, table, callback );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[0] ) {\n\t\t\tparent = value && value.parentNode;\n\n\t\t\t// If we're in a fragment, just use that instead of building a new one\n\t\t\tif ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {\n\t\t\t\tresults = { fragment: parent };\n\n\t\t\t} else {\n\t\t\t\tresults = jQuery.buildFragment( args, this, scripts );\n\t\t\t}\n\n\t\t\tfragment = results.fragment;\n\n\t\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\t\tfirst = fragment = fragment.firstChild;\n\t\t\t} else {\n\t\t\t\tfirst = fragment.firstChild;\n\t\t\t}\n\n\t\t\tif ( first ) {\n\t\t\t\ttable = table && jQuery.nodeName( first, \"tr\" );\n\n\t\t\t\tfor ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {\n\t\t\t\t\tcallback.call(\n\t\t\t\t\t\ttable ?\n\t\t\t\t\t\t\troot(this[i], first) :\n\t\t\t\t\t\t\tthis[i],\n\t\t\t\t\t\t// Make sure that we do not leak memory by inadvertently discarding\n\t\t\t\t\t\t// the original fragment (which might have attached data) instead of\n\t\t\t\t\t\t// using it; in addition, use the original fragment object for the last\n\t\t\t\t\t\t// item instead of first because it can end up being emptied incorrectly\n\t\t\t\t\t\t// in certain situations (Bug #8070).\n\t\t\t\t\t\t// Fragments from the fragment cache must always be cloned and never used\n\t\t\t\t\t\t// in place.\n\t\t\t\t\t\tresults.cacheable || ( l > 1 && i < lastIndex ) ?\n\t\t\t\t\t\t\tjQuery.clone( fragment, true, true ) :\n\t\t\t\t\t\t\tfragment\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( scripts.length ) {\n\t\t\t\tjQuery.each( scripts, function( i, elem ) {\n\t\t\t\t\tif ( elem.src ) {\n\t\t\t\t\t\tjQuery.ajax({\n\t\t\t\t\t\t\ttype: \"GET\",\n\t\t\t\t\t\t\tglobal: false,\n\t\t\t\t\t\t\turl: elem.src,\n\t\t\t\t\t\t\tasync: false,\n\t\t\t\t\t\t\tdataType: \"script\"\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tjQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || \"\" ).replace( rcleanScript, \"/*$0*/\" ) );\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( elem.parentNode ) {\n\t\t\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n});\n\nfunction root( elem, cur ) {\n\treturn jQuery.nodeName(elem, \"table\") ?\n\t\t(elem.getElementsByTagName(\"tbody\")[0] ||\n\t\telem.appendChild(elem.ownerDocument.createElement(\"tbody\"))) :\n\t\telem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\n\tif ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {\n\t\treturn;\n\t}\n\n\tvar type, i, l,\n\t\toldData = jQuery._data( src ),\n\t\tcurData = jQuery._data( dest, oldData ),\n\t\tevents = oldData.events;\n\n\tif ( events ) {\n\t\tdelete curData.handle;\n\t\tcurData.events = {};\n\n\t\tfor ( type in events ) {\n\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t// make the cloned public data object a copy from the original\n\tif ( curData.data ) {\n\t\tcurData.data = jQuery.extend( {}, curData.data );\n\t}\n}\n\nfunction cloneFixAttributes( src, dest ) {\n\tvar nodeName;\n\n\t// We do not need to do anything for non-Elements\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// clearAttributes removes the attributes, which we don't want,\n\t// but also removes the attachEvent events, which we *do* want\n\tif ( dest.clearAttributes ) {\n\t\tdest.clearAttributes();\n\t}\n\n\t// mergeAttributes, in contrast, only merges back on the\n\t// original attributes, not the events\n\tif ( dest.mergeAttributes ) {\n\t\tdest.mergeAttributes( src );\n\t}\n\n\tnodeName = dest.nodeName.toLowerCase();\n\n\t// IE6-8 fail to clone children inside object elements that use\n\t// the proprietary classid attribute value (rather than the type\n\t// attribute) to identify the type of content to display\n\tif ( nodeName === \"object\" ) {\n\t\tdest.outerHTML = src.outerHTML;\n\n\t} else if ( nodeName === \"input\" && (src.type === \"checkbox\" || src.type === \"radio\") ) {\n\t\t// IE6-8 fails to persist the checked state of a cloned checkbox\n\t\t// or radio button. Worse, IE6-7 fail to give the cloned element\n\t\t// a checked appearance if the defaultChecked value isn't also set\n\t\tif ( src.checked ) {\n\t\t\tdest.defaultChecked = dest.checked = src.checked;\n\t\t}\n\n\t\t// IE6-7 get confused and end up setting the value of a cloned\n\t\t// checkbox/radio button to an empty string instead of \"on\"\n\t\tif ( dest.value !== src.value ) {\n\t\t\tdest.value = src.value;\n\t\t}\n\n\t// IE6-8 fails to return the selected option to the default selected\n\t// state when cloning options\n\t} else if ( nodeName === \"option\" ) {\n\t\tdest.selected = src.defaultSelected;\n\n\t// IE6-8 fails to set the defaultValue to the correct value when\n\t// cloning other types of input fields\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\n\t// IE blanks contents when cloning scripts\n\t} else if ( nodeName === \"script\" && dest.text !== src.text ) {\n\t\tdest.text = src.text;\n\t}\n\n\t// Event data gets referenced instead of copied if the expando\n\t// gets copied too\n\tdest.removeAttribute( jQuery.expando );\n\n\t// Clear flags for bubbling special change/submit events, they must\n\t// be reattached when the newly cloned events are first activated\n\tdest.removeAttribute( \"_submit_attached\" );\n\tdest.removeAttribute( \"_change_attached\" );\n}\n\njQuery.buildFragment = function( args, nodes, scripts ) {\n\tvar fragment, cacheable, cacheresults, doc,\n\tfirst = args[ 0 ];\n\n\t// nodes may contain either an explicit document object,\n\t// a jQuery collection or context object.\n\t// If nodes[0] contains a valid object to assign to doc\n\tif ( nodes && nodes[0] ) {\n\t\tdoc = nodes[0].ownerDocument || nodes[0];\n\t}\n\n\t// Ensure that an attr object doesn't incorrectly stand in as a document object\n\t// Chrome and Firefox seem to allow this to occur and will throw exception\n\t// Fixes #8950\n\tif ( !doc.createDocumentFragment ) {\n\t\tdoc = document;\n\t}\n\n\t// Only cache \"small\" (1/2 KB) HTML strings that are associated with the main document\n\t// Cloning options loses the selected state, so don't cache them\n\t// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment\n\t// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache\n\t// Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501\n\tif ( args.length === 1 && typeof first === \"string\" && first.length < 512 && doc === document &&\n\t\tfirst.charAt(0) === \"<\" && !rnocache.test( first ) &&\n\t\t(jQuery.support.checkClone || !rchecked.test( first )) &&\n\t\t(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {\n\n\t\tcacheable = true;\n\n\t\tcacheresults = jQuery.fragments[ first ];\n\t\tif ( cacheresults && cacheresults !== 1 ) {\n\t\t\tfragment = cacheresults;\n\t\t}\n\t}\n\n\tif ( !fragment ) {\n\t\tfragment = doc.createDocumentFragment();\n\t\tjQuery.clean( args, doc, fragment, scripts );\n\t}\n\n\tif ( cacheable ) {\n\t\tjQuery.fragments[ first ] = cacheresults ? fragment : 1;\n\t}\n\n\treturn { fragment: fragment, cacheable: cacheable };\n};\n\njQuery.fragments = {};\n\njQuery.each({\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar ret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tparent = this.length === 1 && this[0].parentNode;\n\n\t\tif ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {\n\t\t\tinsert[ original ]( this[0] );\n\t\t\treturn this;\n\n\t\t} else {\n\t\t\tfor ( var i = 0, l = insert.length; i < l; i++ ) {\n\t\t\t\tvar elems = ( i > 0 ? this.clone(true) : this ).get();\n\t\t\t\tjQuery( insert[i] )[ original ]( elems );\n\t\t\t\tret = ret.concat( elems );\n\t\t\t}\n\n\t\t\treturn this.pushStack( ret, name, insert.selector );\n\t\t}\n\t};\n});\n\nfunction getAll( elem ) {\n\tif ( typeof elem.getElementsByTagName !== \"undefined\" ) {\n\t\treturn elem.getElementsByTagName( \"*\" );\n\n\t} else if ( typeof elem.querySelectorAll !== \"undefined\" ) {\n\t\treturn elem.querySelectorAll( \"*\" );\n\n\t} else {\n\t\treturn [];\n\t}\n}\n\n// Used in clean, fixes the defaultChecked property\nfunction fixDefaultChecked( elem ) {\n\tif ( elem.type === \"checkbox\" || elem.type === \"radio\" ) {\n\t\telem.defaultChecked = elem.checked;\n\t}\n}\n// Finds all inputs and passes them to fixDefaultChecked\nfunction findInputs( elem ) {\n\tvar nodeName = ( elem.nodeName || \"\" ).toLowerCase();\n\tif ( nodeName === \"input\" ) {\n\t\tfixDefaultChecked( elem );\n\t// Skip scripts, get other children\n\t} else if ( nodeName !== \"script\" && typeof elem.getElementsByTagName !== \"undefined\" ) {\n\t\tjQuery.grep( elem.getElementsByTagName(\"input\"), fixDefaultChecked );\n\t}\n}\n\n// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js\nfunction shimCloneNode( elem ) {\n\tvar div = document.createElement( \"div\" );\n\tsafeFragment.appendChild( div );\n\n\tdiv.innerHTML = elem.outerHTML;\n\treturn div.firstChild;\n}\n\njQuery.extend({\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar srcElements,\n\t\t\tdestElements,\n\t\t\ti,\n\t\t\t// IE<=8 does not properly clone detached, unknown element nodes\n\t\t\tclone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( \"<\" + elem.nodeName + \">\" ) ?\n\t\t\t\telem.cloneNode( true ) :\n\t\t\t\tshimCloneNode( elem );\n\n\t\tif ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&\n\t\t\t\t(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {\n\t\t\t// IE copies events bound via attachEvent when using cloneNode.\n\t\t\t// Calling detachEvent on the clone will also remove the events\n\t\t\t// from the original. In order to get around this, we use some\n\t\t\t// proprietary methods to clear the events. Thanks to MooTools\n\t\t\t// guys for this hotness.\n\n\t\t\tcloneFixAttributes( elem, clone );\n\n\t\t\t// Using Sizzle here is crazy slow, so we use getElementsByTagName instead\n\t\t\tsrcElements = getAll( elem );\n\t\t\tdestElements = getAll( clone );\n\n\t\t\t// Weird iteration because IE will replace the length property\n\t\t\t// with an element if you are cloning the body and one of the\n\t\t\t// elements on the page has a name or id of \"length\"\n\t\t\tfor ( i = 0; srcElements[i]; ++i ) {\n\t\t\t\t// Ensure that the destination node is not null; Fixes #9587\n\t\t\t\tif ( destElements[i] ) {\n\t\t\t\t\tcloneFixAttributes( srcElements[i], destElements[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tcloneCopyEvent( elem, clone );\n\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = getAll( elem );\n\t\t\t\tdestElements = getAll( clone );\n\n\t\t\t\tfor ( i = 0; srcElements[i]; ++i ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[i], destElements[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsrcElements = destElements = null;\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tclean: function( elems, context, fragment, scripts ) {\n\t\tvar checkScriptType, script, j,\n\t\t\t\tret = [];\n\n\t\tcontext = context || document;\n\n\t\t// !context.createElement fails in IE with an error but returns typeof 'object'\n\t\tif ( typeof context.createElement === \"undefined\" ) {\n\t\t\tcontext = context.ownerDocument || context[0] && context[0].ownerDocument || document;\n\t\t}\n\n\t\tfor ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( typeof elem === \"number\" ) {\n\t\t\t\telem += \"\";\n\t\t\t}\n\n\t\t\tif ( !elem ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Convert html string into DOM nodes\n\t\t\tif ( typeof elem === \"string\" ) {\n\t\t\t\tif ( !rhtml.test( elem ) ) {\n\t\t\t\t\telem = context.createTextNode( elem );\n\t\t\t\t} else {\n\t\t\t\t\t// Fix \"XHTML\"-style tags in all browsers\n\t\t\t\t\telem = elem.replace(rxhtmlTag, \"<$1></$2>\");\n\n\t\t\t\t\t// Trim whitespace, otherwise indexOf won't work as expected\n\t\t\t\t\tvar tag = ( rtagName.exec( elem ) || [\"\", \"\"] )[1].toLowerCase(),\n\t\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default,\n\t\t\t\t\t\tdepth = wrap[0],\n\t\t\t\t\t\tdiv = context.createElement(\"div\"),\n\t\t\t\t\t\tsafeChildNodes = safeFragment.childNodes,\n\t\t\t\t\t\tremove;\n\n\t\t\t\t\t// Append wrapper element to unknown element safe doc fragment\n\t\t\t\t\tif ( context === document ) {\n\t\t\t\t\t\t// Use the fragment we've already created for this document\n\t\t\t\t\t\tsafeFragment.appendChild( div );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Use a fragment created with the owner document\n\t\t\t\t\t\tcreateSafeFragment( context ).appendChild( div );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Go to html and back, then peel off extra wrappers\n\t\t\t\t\tdiv.innerHTML = wrap[1] + elem + wrap[2];\n\n\t\t\t\t\t// Move to the right depth\n\t\t\t\t\twhile ( depth-- ) {\n\t\t\t\t\t\tdiv = div.lastChild;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove IE's autoinserted <tbody> from table fragments\n\t\t\t\t\tif ( !jQuery.support.tbody ) {\n\n\t\t\t\t\t\t// String was a <table>, *may* have spurious <tbody>\n\t\t\t\t\t\tvar hasBody = rtbody.test(elem),\n\t\t\t\t\t\t\ttbody = tag === \"table\" && !hasBody ?\n\t\t\t\t\t\t\t\tdiv.firstChild && div.firstChild.childNodes :\n\n\t\t\t\t\t\t\t\t// String was a bare <thead> or <tfoot>\n\t\t\t\t\t\t\t\twrap[1] === \"<table>\" && !hasBody ?\n\t\t\t\t\t\t\t\t\tdiv.childNodes :\n\t\t\t\t\t\t\t\t\t[];\n\n\t\t\t\t\t\tfor ( j = tbody.length - 1; j >= 0 ; --j ) {\n\t\t\t\t\t\t\tif ( jQuery.nodeName( tbody[ j ], \"tbody\" ) && !tbody[ j ].childNodes.length ) {\n\t\t\t\t\t\t\t\ttbody[ j ].parentNode.removeChild( tbody[ j ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// IE completely kills leading whitespace when innerHTML is used\n\t\t\t\t\tif ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n\t\t\t\t\t\tdiv.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );\n\t\t\t\t\t}\n\n\t\t\t\t\telem = div.childNodes;\n\n\t\t\t\t\t// Clear elements from DocumentFragment (safeFragment or otherwise)\n\t\t\t\t\t// to avoid hoarding elements. Fixes #11356\n\t\t\t\t\tif ( div ) {\n\t\t\t\t\t\tdiv.parentNode.removeChild( div );\n\n\t\t\t\t\t\t// Guard against -1 index exceptions in FF3.6\n\t\t\t\t\t\tif ( safeChildNodes.length > 0 ) {\n\t\t\t\t\t\t\tremove = safeChildNodes[ safeChildNodes.length - 1 ];\n\n\t\t\t\t\t\t\tif ( remove && remove.parentNode ) {\n\t\t\t\t\t\t\t\tremove.parentNode.removeChild( remove );\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\n\t\t\t// Resets defaultChecked for any radios and checkboxes\n\t\t\t// about to be appended to the DOM in IE 6/7 (#8060)\n\t\t\tvar len;\n\t\t\tif ( !jQuery.support.appendChecked ) {\n\t\t\t\tif ( elem[0] && typeof (len = elem.length) === \"number\" ) {\n\t\t\t\t\tfor ( j = 0; j < len; j++ ) {\n\t\t\t\t\t\tfindInputs( elem[j] );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tfindInputs( elem );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( elem.nodeType ) {\n\t\t\t\tret.push( elem );\n\t\t\t} else {\n\t\t\t\tret = jQuery.merge( ret, elem );\n\t\t\t}\n\t\t}\n\n\t\tif ( fragment ) {\n\t\t\tcheckScriptType = function( elem ) {\n\t\t\t\treturn !elem.type || rscriptType.test( elem.type );\n\t\t\t};\n\t\t\tfor ( i = 0; ret[i]; i++ ) {\n\t\t\t\tscript = ret[i];\n\t\t\t\tif ( scripts && jQuery.nodeName( script, \"script\" ) && (!script.type || rscriptType.test( script.type )) ) {\n\t\t\t\t\tscripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );\n\n\t\t\t\t} else {\n\t\t\t\t\tif ( script.nodeType === 1 ) {\n\t\t\t\t\t\tvar jsTags = jQuery.grep( script.getElementsByTagName( \"script\" ), checkScriptType );\n\n\t\t\t\t\t\tret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );\n\t\t\t\t\t}\n\t\t\t\t\tfragment.appendChild( script );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, id,\n\t\t\tcache = jQuery.cache,\n\t\t\tspecial = jQuery.event.special,\n\t\t\tdeleteExpando = jQuery.support.deleteExpando;\n\n\t\tfor ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tid = elem[ jQuery.expando ];\n\n\t\t\tif ( id ) {\n\t\t\t\tdata = cache[ id ];\n\n\t\t\t\tif ( data && data.events ) {\n\t\t\t\t\tfor ( var type in data.events ) {\n\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Null the DOM reference to avoid IE6/7/8 leak (#7054)\n\t\t\t\t\tif ( data.handle ) {\n\t\t\t\t\t\tdata.handle.elem = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( deleteExpando ) {\n\t\t\t\t\tdelete elem[ jQuery.expando ];\n\n\t\t\t\t} else if ( elem.removeAttribute ) {\n\t\t\t\t\telem.removeAttribute( jQuery.expando );\n\t\t\t\t}\n\n\t\t\t\tdelete cache[ id ];\n\t\t\t}\n\t\t}\n\t}\n});\n\n\n\n\nvar ralpha = /alpha\\([^)]*\\)/i,\n\tropacity = /opacity=([^)]*)/,\n\t// fixed for IE9, see #8346\n\trupper = /([A-Z]|^ms)/g,\n\trnum = /^[\\-+]?(?:\\d*\\.)?\\d+$/i,\n\trnumnonpx = /^-?(?:\\d*\\.)?\\d+(?!px)[^\\d\\s]+$/i,\n\trrelNum = /^([\\-+])=([\\-+.\\de]+)/,\n\trmargin = /^margin/,\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\n\t// order is important!\n\tcssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ],\n\n\tcurCSS,\n\n\tgetComputedStyle,\n\tcurrentStyle;\n\njQuery.fn.css = function( name, value ) {\n\treturn jQuery.access( this, function( elem, name, value ) {\n\t\treturn value !== undefined ?\n\t\t\tjQuery.style( elem, name, value ) :\n\t\t\tjQuery.css( elem, name );\n\t}, name, value, arguments.length > 1 );\n};\n\njQuery.extend({\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\n\t\t\t\t} else {\n\t\t\t\t\treturn elem.style.opacity;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Exclude the following css properties to add px\n\tcssNumber: {\n\t\t\"fillOpacity\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t// normalize float css property\n\t\t\"float\": jQuery.support.cssFloat ? \"cssFloat\" : \"styleFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, origName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style, hooks = jQuery.cssHooks[ origName ];\n\n\t\tname = jQuery.cssProps[ origName ] || origName;\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// convert relative number strings (+= or -=) to relative numbers. #7345\n\t\t\tif ( type === \"string\" && (ret = rrelNum.exec( value )) ) {\n\t\t\t\tvalue = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that NaN and null values aren't set. See: #7116\n\t\t\tif ( value == null || type === \"number\" && isNaN( value ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add 'px' to the (except for certain CSS properties)\n\t\t\tif ( type === \"number\" && !jQuery.cssNumber[ origName ] ) {\n\t\t\t\tvalue += \"px\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !(\"set\" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {\n\t\t\t\t// Wrapped to prevent IE from throwing errors when 'invalid' values are provided\n\t\t\t\t// Fixes bug #5509\n\t\t\t\ttry {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t} else {\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra ) {\n\t\tvar ret, hooks;\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.camelCase( name );\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tname = jQuery.cssProps[ name ] || name;\n\n\t\t// cssFloat needs a special treatment\n\t\tif ( name === \"cssFloat\" ) {\n\t\t\tname = \"float\";\n\t\t}\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {\n\t\t\treturn ret;\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\t} else if ( curCSS ) {\n\t\t\treturn curCSS( elem, name );\n\t\t}\n\t},\n\n\t// A method for quickly swapping in/out CSS properties to get correct calculations\n\tswap: function( elem, options, callback ) {\n\t\tvar old = {},\n\t\t\tret, name;\n\n\t\t// Remember the old values, and insert the new ones\n\t\tfor ( name in options ) {\n\t\t\told[ name ] = elem.style[ name ];\n\t\t\telem.style[ name ] = options[ name ];\n\t\t}\n\n\t\tret = callback.call( elem );\n\n\t\t// Revert the old values\n\t\tfor ( name in options ) {\n\t\t\telem.style[ name ] = old[ name ];\n\t\t}\n\n\t\treturn ret;\n\t}\n});\n\n// DEPRECATED in 1.3, Use jQuery.css() instead\njQuery.curCSS = jQuery.css;\n\nif ( document.defaultView && document.defaultView.getComputedStyle ) {\n\tgetComputedStyle = function( elem, name ) {\n\t\tvar ret, defaultView, computedStyle, width,\n\t\t\tstyle = elem.style;\n\n\t\tname = name.replace( rupper, \"-$1\" ).toLowerCase();\n\n\t\tif ( (defaultView = elem.ownerDocument.defaultView) &&\n\t\t\t\t(computedStyle = defaultView.getComputedStyle( elem, null )) ) {\n\n\t\t\tret = computedStyle.getPropertyValue( name );\n\t\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {\n\t\t\t\tret = jQuery.style( elem, name );\n\t\t\t}\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// WebKit uses \"computed value (percentage if specified)\" instead of \"used value\" for margins\n\t\t// which is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values\n\t\tif ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) {\n\t\t\twidth = style.width;\n\t\t\tstyle.width = ret;\n\t\t\tret = computedStyle.width;\n\t\t\tstyle.width = width;\n\t\t}\n\n\t\treturn ret;\n\t};\n}\n\nif ( document.documentElement.currentStyle ) {\n\tcurrentStyle = function( elem, name ) {\n\t\tvar left, rsLeft, uncomputed,\n\t\t\tret = elem.currentStyle && elem.currentStyle[ name ],\n\t\t\tstyle = elem.style;\n\n\t\t// Avoid setting ret to empty string here\n\t\t// so we don't default to auto\n\t\tif ( ret == null && style && (uncomputed = style[ name ]) ) {\n\t\t\tret = uncomputed;\n\t\t}\n\n\t\t// From the awesome hack by Dean Edwards\n\t\t// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291\n\n\t\t// If we're not dealing with a regular pixel number\n\t\t// but a number that has a weird ending, we need to convert it to pixels\n\t\tif ( rnumnonpx.test( ret ) ) {\n\n\t\t\t// Remember the original values\n\t\t\tleft = style.left;\n\t\t\trsLeft = elem.runtimeStyle && elem.runtimeStyle.left;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tif ( rsLeft ) {\n\t\t\t\telem.runtimeStyle.left = elem.currentStyle.left;\n\t\t\t}\n\t\t\tstyle.left = name === \"fontSize\" ? \"1em\" : ret;\n\t\t\tret = style.pixelLeft + \"px\";\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.left = left;\n\t\t\tif ( rsLeft ) {\n\t\t\t\telem.runtimeStyle.left = rsLeft;\n\t\t\t}\n\t\t}\n\n\t\treturn ret === \"\" ? \"auto\" : ret;\n\t};\n}\n\ncurCSS = getComputedStyle || currentStyle;\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with offset property\n\tvar val = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n\t\ti = name === \"width\" ? 1 : 0,\n\t\tlen = 4;\n\n\tif ( val > 0 ) {\n\t\tif ( extra !== \"border\" ) {\n\t\t\tfor ( ; i < len; i += 2 ) {\n\t\t\t\tif ( !extra ) {\n\t\t\t\t\tval -= parseFloat( jQuery.css( elem, \"padding\" + cssExpand[ i ] ) ) || 0;\n\t\t\t\t}\n\t\t\t\tif ( extra === \"margin\" ) {\n\t\t\t\t\tval += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;\n\t\t\t\t} else {\n\t\t\t\t\tval -= parseFloat( jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\" ) ) || 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn val + \"px\";\n\t}\n\n\t// Fall back to computed then uncomputed css if necessary\n\tval = curCSS( elem, name );\n\tif ( val < 0 || val == null ) {\n\t\tval = elem.style[ name ];\n\t}\n\n\t// Computed unit is not pixels. Stop here and return.\n\tif ( rnumnonpx.test(val) ) {\n\t\treturn val;\n\t}\n\n\t// Normalize \"\", auto, and prepare for extra\n\tval = parseFloat( val ) || 0;\n\n\t// Add padding, border, margin\n\tif ( extra ) {\n\t\tfor ( ; i < len; i += 2 ) {\n\t\t\tval += parseFloat( jQuery.css( elem, \"padding\" + cssExpand[ i ] ) ) || 0;\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += parseFloat( jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\" ) ) || 0;\n\t\t\t}\n\t\t\tif ( extra === \"margin\" ) {\n\t\t\t\tval += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val + \"px\";\n}\n\njQuery.each([ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\t\t\t\tif ( elem.offsetWidth !== 0 ) {\n\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t} else {\n\t\t\t\t\treturn jQuery.swap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value ) {\n\t\t\treturn rnum.test( value ) ?\n\t\t\t\tvalue + \"px\" :\n\t\t\t\tvalue;\n\t\t}\n\t};\n});\n\nif ( !jQuery.support.opacity ) {\n\tjQuery.cssHooks.opacity = {\n\t\tget: function( elem, computed ) {\n\t\t\t// IE uses filters for opacity\n\t\t\treturn ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || \"\" ) ?\n\t\t\t\t( parseFloat( RegExp.$1 ) / 100 ) + \"\" :\n\t\t\t\tcomputed ? \"1\" : \"\";\n\t\t},\n\n\t\tset: function( elem, value ) {\n\t\t\tvar style = elem.style,\n\t\t\t\tcurrentStyle = elem.currentStyle,\n\t\t\t\topacity = jQuery.isNumeric( value ) ? \"alpha(opacity=\" + value * 100 + \")\" : \"\",\n\t\t\t\tfilter = currentStyle && currentStyle.filter || style.filter || \"\";\n\n\t\t\t// IE has trouble with opacity if it does not have layout\n\t\t\t// Force it by setting the zoom level\n\t\t\tstyle.zoom = 1;\n\n\t\t\t// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652\n\t\t\tif ( value >= 1 && jQuery.trim( filter.replace( ralpha, \"\" ) ) === \"\" ) {\n\n\t\t\t\t// Setting style.filter to null, \"\" & \" \" still leave \"filter:\" in the cssText\n\t\t\t\t// if \"filter:\" is present at all, clearType is disabled, we want to avoid this\n\t\t\t\t// style.removeAttribute is IE Only, but so apparently is this code path...\n\t\t\t\tstyle.removeAttribute( \"filter\" );\n\n\t\t\t\t// if there there is no filter style applied in a css rule, we are done\n\t\t\t\tif ( currentStyle && !currentStyle.filter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// otherwise, set new filter values\n\t\t\tstyle.filter = ralpha.test( filter ) ?\n\t\t\t\tfilter.replace( ralpha, opacity ) :\n\t\t\t\tfilter + \" \" + opacity;\n\t\t}\n\t};\n}\n\njQuery(function() {\n\t// This hook cannot be added until DOM ready because the support test\n\t// for it is not run until after DOM ready\n\tif ( !jQuery.support.reliableMarginRight ) {\n\t\tjQuery.cssHooks.marginRight = {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t\t// Work around by temporarily setting element display to inline-block\n\t\t\t\treturn jQuery.swap( elem, { \"display\": \"inline-block\" }, function() {\n\t\t\t\t\tif ( computed ) {\n\t\t\t\t\t\treturn curCSS( elem, \"margin-right\" );\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.style.marginRight;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t}\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.hidden = function( elem ) {\n\t\tvar width = elem.offsetWidth,\n\t\t\theight = elem.offsetHeight;\n\n\t\treturn ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, \"display\" )) === \"none\");\n\t};\n\n\tjQuery.expr.filters.visible = function( elem ) {\n\t\treturn !jQuery.expr.filters.hidden( elem );\n\t};\n}\n\n// These hooks are used by animate to expand properties\njQuery.each({\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i,\n\n\t\t\t\t// assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split(\" \") : [ value ],\n\t\t\t\texpanded = {};\n\n\t\t\tfor ( i = 0; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n});\n\n\n\n\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trhash = /#.*$/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg, // IE leaves an \\r character at EOL\n\trinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app\\-storage|.+\\-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\trquery = /\\?/,\n\trscript = /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,\n\trselectTextarea = /^(?:select|textarea)/i,\n\trspacesAjax = /\\s+/,\n\trts = /([?&])_=[^&]*/,\n\trurl = /^([\\w\\+\\.\\-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+))?)?/,\n\n\t// Keep a copy of the old load method\n\t_load = jQuery.fn.load,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Document location\n\tajaxLocation,\n\n\t// Document location segments\n\tajaxLocParts,\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = [\"*/\"] + [\"*\"];\n\n// #8138, IE may throw an exception when accessing\n// a field from window.location if document.domain has been set\ntry {\n\tajaxLocation = location.href;\n} catch( e ) {\n\t// Use the href attribute of an A element\n\t// since IE will modify it given document.location\n\tajaxLocation = document.createElement( \"a\" );\n\tajaxLocation.href = \"\";\n\tajaxLocation = ajaxLocation.href;\n}\n\n// Segment location into parts\najaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\t\t\tvar dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),\n\t\t\t\ti = 0,\n\t\t\t\tlength = dataTypes.length,\n\t\t\t\tdataType,\n\t\t\t\tlist,\n\t\t\t\tplaceBefore;\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tdataType = dataTypes[ i ];\n\t\t\t\t// We control if we're asked to add before\n\t\t\t\t// any existing element\n\t\t\t\tplaceBefore = /^\\+/.test( dataType );\n\t\t\t\tif ( placeBefore ) {\n\t\t\t\t\tdataType = dataType.substr( 1 ) || \"*\";\n\t\t\t\t}\n\t\t\t\tlist = structure[ dataType ] = structure[ dataType ] || [];\n\t\t\t\t// then we add to the structure accordingly\n\t\t\t\tlist[ placeBefore ? \"unshift\" : \"push\" ]( func );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,\n\t\tdataType /* internal */, inspected /* internal */ ) {\n\n\tdataType = dataType || options.dataTypes[ 0 ];\n\tinspected = inspected || {};\n\n\tinspected[ dataType ] = true;\n\n\tvar list = structure[ dataType ],\n\t\ti = 0,\n\t\tlength = list ? list.length : 0,\n\t\texecuteOnly = ( structure === prefilters ),\n\t\tselection;\n\n\tfor ( ; i < length && ( executeOnly || !selection ); i++ ) {\n\t\tselection = list[ i ]( options, originalOptions, jqXHR );\n\t\t// If we got redirected to another dataType\n\t\t// we try there if executing only and not done already\n\t\tif ( typeof selection === \"string\" ) {\n\t\t\tif ( !executeOnly || inspected[ selection ] ) {\n\t\t\t\tselection = undefined;\n\t\t\t} else {\n\t\t\t\toptions.dataTypes.unshift( selection );\n\t\t\t\tselection = inspectPrefiltersOrTransports(\n\t\t\t\t\t\tstructure, options, originalOptions, jqXHR, selection, inspected );\n\t\t\t}\n\t\t}\n\t}\n\t// If we're only executing or nothing was selected\n\t// we try the catchall dataType if not done already\n\tif ( ( executeOnly || !selection ) && !inspected[ \"*\" ] ) {\n\t\tselection = inspectPrefiltersOrTransports(\n\t\t\t\tstructure, options, originalOptions, jqXHR, \"*\", inspected );\n\t}\n\t// unnecessary when only executing (prefilters)\n\t// but it'll be ignored by the caller in that case\n\treturn selection;\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n}\n\njQuery.fn.extend({\n\tload: function( url, params, callback ) {\n\t\tif ( typeof url !== \"string\" && _load ) {\n\t\t\treturn _load.apply( this, arguments );\n\n\t\t// Don't do a request if no elements are being requested\n\t\t} else if ( !this.length ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tvar off = url.indexOf( \" \" );\n\t\tif ( off >= 0 ) {\n\t\t\tvar selector = url.slice( off, url.length );\n\t\t\turl = url.slice( 0, off );\n\t\t}\n\n\t\t// Default to a GET request\n\t\tvar type = \"GET\";\n\n\t\t// If the second parameter was provided\n\t\tif ( params ) {\n\t\t\t// If it's a function\n\t\t\tif ( jQuery.isFunction( params ) ) {\n\t\t\t\t// We assume that it's the callback\n\t\t\t\tcallback = params;\n\t\t\t\tparams = undefined;\n\n\t\t\t// Otherwise, build a param string\n\t\t\t} else if ( typeof params === \"object\" ) {\n\t\t\t\tparams = jQuery.param( params, jQuery.ajaxSettings.traditional );\n\t\t\t\ttype = \"POST\";\n\t\t\t}\n\t\t}\n\n\t\tvar self = this;\n\n\t\t// Request the remote document\n\t\tjQuery.ajax({\n\t\t\turl: url,\n\t\t\ttype: type,\n\t\t\tdataType: \"html\",\n\t\t\tdata: params,\n\t\t\t// Complete callback (responseText is used internally)\n\t\t\tcomplete: function( jqXHR, status, responseText ) {\n\t\t\t\t// Store the response as specified by the jqXHR object\n\t\t\t\tresponseText = jqXHR.responseText;\n\t\t\t\t// If successful, inject the HTML into all the matched elements\n\t\t\t\tif ( jqXHR.isResolved() ) {\n\t\t\t\t\t// #4825: Get the actual response in case\n\t\t\t\t\t// a dataFilter is present in ajaxSettings\n\t\t\t\t\tjqXHR.done(function( r ) {\n\t\t\t\t\t\tresponseText = r;\n\t\t\t\t\t});\n\t\t\t\t\t// See if a selector was specified\n\t\t\t\t\tself.html( selector ?\n\t\t\t\t\t\t// Create a dummy div to hold the results\n\t\t\t\t\t\tjQuery(\"<div>\")\n\t\t\t\t\t\t\t// inject the contents of the document in, removing the scripts\n\t\t\t\t\t\t\t// to avoid any 'Permission Denied' errors in IE\n\t\t\t\t\t\t\t.append(responseText.replace(rscript, \"\"))\n\n\t\t\t\t\t\t\t// Locate the specified elements\n\t\t\t\t\t\t\t.find(selector) :\n\n\t\t\t\t\t\t// If not, just inject the full result\n\t\t\t\t\t\tresponseText );\n\t\t\t\t}\n\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tself.each( callback, [ responseText, status, jqXHR ] );\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t},\n\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\n\tserializeArray: function() {\n\t\treturn this.map(function(){\n\t\t\treturn this.elements ? jQuery.makeArray( this.elements ) : this;\n\t\t})\n\t\t.filter(function(){\n\t\t\treturn this.name && !this.disabled &&\n\t\t\t\t( this.checked || rselectTextarea.test( this.nodeName ) ||\n\t\t\t\t\trinput.test( this.type ) );\n\t\t})\n\t\t.map(function( i, elem ){\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray( val ) ?\n\t\t\t\t\tjQuery.map( val, function( val, i ){\n\t\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t\t}) :\n\t\t\t\t\t{ name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t}).get();\n\t}\n});\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( \"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split( \" \" ), function( i, o ){\n\tjQuery.fn[ o ] = function( f ){\n\t\treturn this.on( o, f );\n\t};\n});\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\t\t// shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\treturn jQuery.ajax({\n\t\t\ttype: method,\n\t\t\turl: url,\n\t\t\tdata: data,\n\t\t\tsuccess: callback,\n\t\t\tdataType: type\n\t\t});\n\t};\n});\n\njQuery.extend({\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\tif ( settings ) {\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( target, jQuery.ajaxSettings );\n\t\t} else {\n\t\t\t// Extending ajaxSettings\n\t\t\tsettings = target;\n\t\t\ttarget = jQuery.ajaxSettings;\n\t\t}\n\t\tajaxExtend( target, settings );\n\t\treturn target;\n\t},\n\n\tajaxSettings: {\n\t\turl: ajaxLocation,\n\t\tisLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n\t\tglobal: true,\n\t\ttype: \"GET\",\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\t\tprocessData: true,\n\t\tasync: true,\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\thtml: \"text/html\",\n\t\t\ttext: \"text/plain\",\n\t\t\tjson: \"application/json, text/javascript\",\n\t\t\t\"*\": allTypes\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /xml/,\n\t\t\thtml: /html/,\n\t\t\tjson: /json/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\"\n\t\t},\n\n\t\t// List of data converters\n\t\t// 1) key format is \"source_type destination_type\" (a single space in-between)\n\t\t// 2) the catchall symbol \"*\" can be used for source_type\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": window.String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": jQuery.parseJSON,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\tcontext: true,\n\t\t\turl: true\n\t\t}\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar // Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\t\t\t// Context for global events\n\t\t\t// It's the callbackContext if one was provided in the options\n\t\t\t// and if it's a DOM node or a jQuery collection\n\t\t\tglobalEventContext = callbackContext !== s &&\n\t\t\t\t( callbackContext.nodeType || callbackContext instanceof jQuery ) ?\n\t\t\t\t\t\tjQuery( callbackContext ) : jQuery.event,\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\t\t\t// ifModified key\n\t\t\tifModifiedKey,\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\t\t\t// transport\n\t\t\ttransport,\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\t\t\t// Cross-domain detection vars\n\t\t\tparts,\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\t\t\t// Loop variable\n\t\t\ti,\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\t\tname = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn state === 2 ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( state === 2 ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[1].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match === undefined ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tstatusText = statusText || \"abort\";\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( statusText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, statusText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Callback for when everything is done\n\t\t// It is defined here because jslint complains if it is declared\n\t\t// at the end of the function (which would be more logical and readable)\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\n\t\t\t// Called once\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// State is \"done\" now\n\t\t\tstate = 2;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\tclearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\tvar isSuccess,\n\t\t\t\tsuccess,\n\t\t\t\terror,\n\t\t\t\tstatusText = nativeStatusText,\n\t\t\t\tresponse = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,\n\t\t\t\tlastModified,\n\t\t\t\tetag;\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( status >= 200 && status < 300 || status === 304 ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\n\t\t\t\t\tif ( ( lastModified = jqXHR.getResponseHeader( \"Last-Modified\" ) ) ) {\n\t\t\t\t\t\tjQuery.lastModified[ ifModifiedKey ] = lastModified;\n\t\t\t\t\t}\n\t\t\t\t\tif ( ( etag = jqXHR.getResponseHeader( \"Etag\" ) ) ) {\n\t\t\t\t\t\tjQuery.etag[ ifModifiedKey ] = etag;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If not modified\n\t\t\t\tif ( status === 304 ) {\n\n\t\t\t\t\tstatusText = \"notmodified\";\n\t\t\t\t\tisSuccess = true;\n\n\t\t\t\t// If we have data\n\t\t\t\t} else {\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsuccess = ajaxConvert( s, response );\n\t\t\t\t\t\tstatusText = \"success\";\n\t\t\t\t\t\tisSuccess = true;\n\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t// We have a parsererror\n\t\t\t\t\t\tstatusText = \"parsererror\";\n\t\t\t\t\t\terror = e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We extract error from statusText\n\t\t\t\t// then normalize statusText and status for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( !statusText || status ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = \"\" + ( nativeStatusText || statusText );\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajax\" + ( isSuccess ? \"Success\" : \"Error\" ),\n\t\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\n\t\tjqXHR.complete = completeDeferred.add;\n\n\t\t// Status-dependent callbacks\n\t\tjqXHR.statusCode = function( map ) {\n\t\t\tif ( map ) {\n\t\t\t\tvar tmp;\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tfor ( tmp in map ) {\n\t\t\t\t\t\tstatusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttmp = map[ jqXHR.status ];\n\t\t\t\t\tjqXHR.then( tmp, tmp );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this;\n\t\t};\n\n\t\t// Remove hash character (#7531: and string promotion)\n\t\t// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url ) + \"\" ).replace( rhash, \"\" ).replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().split( rspacesAjax );\n\n\t\t// Determine if a cross-domain request is in order\n\t\tif ( s.crossDomain == null ) {\n\t\t\tparts = rurl.exec( s.url.toLowerCase() );\n\t\t\ts.crossDomain = !!( parts &&\n\t\t\t\t( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||\n\t\t\t\t\t( parts[ 3 ] || ( parts[ 1 ] === \"http:\" ? 80 : 443 ) ) !=\n\t\t\t\t\t\t( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === \"http:\" ? 80 : 443 ) ) )\n\t\t\t);\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\tfireGlobals = s.global;\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.data;\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Get ifModifiedKey before adding the anti-cache parameter\n\t\t\tifModifiedKey = s.url;\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\n\t\t\t\tvar ts = jQuery.now(),\n\t\t\t\t\t// try replacing _= if it is there\n\t\t\t\t\tret = s.url.replace( rts, \"$1_=\" + ts );\n\n\t\t\t\t// if nothing was replaced, add timestamp to the end\n\t\t\t\ts.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? \"&\" : \"?\" ) + \"_=\" + ts : \"\" );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tifModifiedKey = ifModifiedKey || s.url;\n\t\t\tif ( jQuery.lastModified[ ifModifiedKey ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ ifModifiedKey ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ ifModifiedKey ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ ifModifiedKey ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n\t\t\t\t// Abort if not done already\n\t\t\t\tjqXHR.abort();\n\t\t\t\treturn false;\n\n\t\t}\n\n\t\t// Install callbacks on deferreds\n\t\tfor ( i in { success: 1, error: 1, complete: 1 } ) {\n\t\t\tjqXHR[ i ]( s[ i ] );\n\t\t}\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = setTimeout( function(){\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tstate = 1;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch (e) {\n\t\t\t\t// Propagate exception as error if not done\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tdone( -1, e );\n\t\t\t\t// Simply rethrow otherwise\n\t\t\t\t} else {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\t// Serialize an array of form elements or a set of\n\t// key/values into a query string\n\tparam: function( a, traditional ) {\n\t\tvar s = [],\n\t\t\tadd = function( key, value ) {\n\t\t\t\t// If value is a function, invoke it and return its value\n\t\t\t\tvalue = jQuery.isFunction( value ) ? value() : value;\n\t\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t\t};\n\n\t\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\t\tif ( traditional === undefined ) {\n\t\t\ttraditional = jQuery.ajaxSettings.traditional;\n\t\t}\n\n\t\t// If an array was passed in, assume that it is an array of form elements.\n\t\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\t\t\t// Serialize the form elements\n\t\t\tjQuery.each( a, function() {\n\t\t\t\tadd( this.name, this.value );\n\t\t\t});\n\n\t\t} else {\n\t\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t\t// did it), otherwise encode params recursively.\n\t\t\tfor ( var prefix in a ) {\n\t\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t\t}\n\t\t}\n\n\t\t// Return the resulting serialization\n\t\treturn s.join( \"&\" ).replace( r20, \"+\" );\n\t}\n});\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tif ( jQuery.isArray( obj ) ) {\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\t\t\t\t// If array item is non-scalar (array or object), encode its\n\t\t\t\t// numeric index to resolve deserialization ambiguity issues.\n\t\t\t\t// Note that rack (as of 1.0.0) can't currently deserialize\n\t\t\t\t// nested arrays properly, and attempting to do so may cause\n\t\t\t\t// a server error. Possible fixes are to modify rack's\n\t\t\t\t// deserialization algorithm or to provide an option or flag\n\t\t\t\t// to force array serialization to be shallow.\n\t\t\t\tbuildParams( prefix + \"[\" + ( typeof v === \"object\" ? i : \"\" ) + \"]\", v, traditional, add );\n\t\t\t}\n\t\t});\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\t\t// Serialize object item.\n\t\tfor ( var name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// This is still on the jQuery object... for now\n// Want to move this to jQuery.ajax some day\njQuery.extend({\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {}\n\n});\n\n/* Handles responses to an ajax request:\n * - sets all responseXXX fields accordingly\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar contents = s.contents,\n\t\tdataTypes = s.dataTypes,\n\t\tresponseFields = s.responseFields,\n\t\tct,\n\t\ttype,\n\t\tfinalDataType,\n\t\tfirstDataType;\n\n\t// Fill responseXXX fields\n\tfor ( type in responseFields ) {\n\t\tif ( type in responses ) {\n\t\t\tjqXHR[ responseFields[type] ] = responses[ type ];\n\t\t}\n\t}\n\n\t// Remove auto dataType and get content-type in the process\n\twhile( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"content-type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[0] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n// Chain conversions given the request and the original response\nfunction ajaxConvert( s, response ) {\n\n\t// Apply the dataFilter if provided\n\tif ( s.dataFilter ) {\n\t\tresponse = s.dataFilter( response, s.dataType );\n\t}\n\n\tvar dataTypes = s.dataTypes,\n\t\tconverters = {},\n\t\ti,\n\t\tkey,\n\t\tlength = dataTypes.length,\n\t\ttmp,\n\t\t// Current and previous dataTypes\n\t\tcurrent = dataTypes[ 0 ],\n\t\tprev,\n\t\t// Conversion expression\n\t\tconversion,\n\t\t// Conversion function\n\t\tconv,\n\t\t// Conversion functions (transitive conversion)\n\t\tconv1,\n\t\tconv2;\n\n\t// For each dataType in the chain\n\tfor ( i = 1; i < length; i++ ) {\n\n\t\t// Create converters map\n\t\t// with lowercased keys\n\t\tif ( i === 1 ) {\n\t\t\tfor ( key in s.converters ) {\n\t\t\t\tif ( typeof key === \"string\" ) {\n\t\t\t\t\tconverters[ key.toLowerCase() ] = s.converters[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Get the dataTypes\n\t\tprev = current;\n\t\tcurrent = dataTypes[ i ];\n\n\t\t// If current is auto dataType, update it to prev\n\t\tif ( current === \"*\" ) {\n\t\t\tcurrent = prev;\n\t\t// If no auto and dataTypes are actually different\n\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t// Get the converter\n\t\t\tconversion = prev + \" \" + current;\n\t\t\tconv = converters[ conversion ] || converters[ \"* \" + current ];\n\n\t\t\t// If there is no direct converter, search transitively\n\t\t\tif ( !conv ) {\n\t\t\t\tconv2 = undefined;\n\t\t\t\tfor ( conv1 in converters ) {\n\t\t\t\t\ttmp = conv1.split( \" \" );\n\t\t\t\t\tif ( tmp[ 0 ] === prev || tmp[ 0 ] === \"*\" ) {\n\t\t\t\t\t\tconv2 = converters[ tmp[1] + \" \" + current ];\n\t\t\t\t\t\tif ( conv2 ) {\n\t\t\t\t\t\t\tconv1 = converters[ conv1 ];\n\t\t\t\t\t\t\tif ( conv1 === true ) {\n\t\t\t\t\t\t\t\tconv = conv2;\n\t\t\t\t\t\t\t} else if ( conv2 === true ) {\n\t\t\t\t\t\t\t\tconv = conv1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\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// If we found no converter, dispatch an error\n\t\t\tif ( !( conv || conv2 ) ) {\n\t\t\t\tjQuery.error( \"No conversion from \" + conversion.replace(\" \",\" to \") );\n\t\t\t}\n\t\t\t// If found converter is not an equivalence\n\t\t\tif ( conv !== true ) {\n\t\t\t\t// Convert with 1 or 2 converters accordingly\n\t\t\t\tresponse = conv ? conv( response ) : conv2( conv1(response) );\n\t\t\t}\n\t\t}\n\t}\n\treturn response;\n}\n\n\n\n\nvar jsc = jQuery.now(),\n\tjsre = /(\\=)\\?(&|$)|\\?\\?/i;\n\n// Default jsonp settings\njQuery.ajaxSetup({\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\treturn jQuery.expando + \"_\" + ( jsc++ );\n\t}\n});\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar inspectData = ( typeof s.data === \"string\" ) && /^application\\/x\\-www\\-form\\-urlencoded/.test( s.contentType );\n\n\tif ( s.dataTypes[ 0 ] === \"jsonp\" ||\n\t\ts.jsonp !== false && ( jsre.test( s.url ) ||\n\t\t\t\tinspectData && jsre.test( s.data ) ) ) {\n\n\t\tvar responseContainer,\n\t\t\tjsonpCallback = s.jsonpCallback =\n\t\t\t\tjQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,\n\t\t\tprevious = window[ jsonpCallback ],\n\t\t\turl = s.url,\n\t\t\tdata = s.data,\n\t\t\treplace = \"$1\" + jsonpCallback + \"$2\";\n\n\t\tif ( s.jsonp !== false ) {\n\t\t\turl = url.replace( jsre, replace );\n\t\t\tif ( s.url === url ) {\n\t\t\t\tif ( inspectData ) {\n\t\t\t\t\tdata = data.replace( jsre, replace );\n\t\t\t\t}\n\t\t\t\tif ( s.data === data ) {\n\t\t\t\t\t// Add callback manually\n\t\t\t\t\turl += (/\\?/.test( url ) ? \"&\" : \"?\") + s.jsonp + \"=\" + jsonpCallback;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ts.url = url;\n\t\ts.data = data;\n\n\t\t// Install callback\n\t\twindow[ jsonpCallback ] = function( response ) {\n\t\t\tresponseContainer = [ response ];\n\t\t};\n\n\t\t// Clean-up function\n\t\tjqXHR.always(function() {\n\t\t\t// Set callback back to previous value\n\t\t\twindow[ jsonpCallback ] = previous;\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( previous ) ) {\n\t\t\t\twindow[ jsonpCallback ]( responseContainer[ 0 ] );\n\t\t\t}\n\t\t});\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[\"script json\"] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( jsonpCallback + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n});\n\n\n\n\n// Install script dataType\njQuery.ajaxSetup({\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /javascript|ecmascript/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n});\n\n// Handle cache's special case and global\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t\ts.global = false;\n\t}\n});\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function(s) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\n\t\tvar script,\n\t\t\thead = document.head || document.getElementsByTagName( \"head\" )[0] || document.documentElement;\n\n\t\treturn {\n\n\t\t\tsend: function( _, callback ) {\n\n\t\t\t\tscript = document.createElement( \"script\" );\n\n\t\t\t\tscript.async = \"async\";\n\n\t\t\t\tif ( s.scriptCharset ) {\n\t\t\t\t\tscript.charset = s.scriptCharset;\n\t\t\t\t}\n\n\t\t\t\tscript.src = s.url;\n\n\t\t\t\t// Attach handlers for all browsers\n\t\t\t\tscript.onload = script.onreadystatechange = function( _, isAbort ) {\n\n\t\t\t\t\tif ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {\n\n\t\t\t\t\t\t// Handle memory leak in IE\n\t\t\t\t\t\tscript.onload = script.onreadystatechange = null;\n\n\t\t\t\t\t\t// Remove the script\n\t\t\t\t\t\tif ( head && script.parentNode ) {\n\t\t\t\t\t\t\thead.removeChild( script );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Dereference the script\n\t\t\t\t\t\tscript = undefined;\n\n\t\t\t\t\t\t// Callback if not abort\n\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\tcallback( 200, \"success\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t// Use insertBefore instead of appendChild  to circumvent an IE6 bug.\n\t\t\t\t// This arises when a base node is used (#2709 and #4378).\n\t\t\t\thead.insertBefore( script, head.firstChild );\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( script ) {\n\t\t\t\t\tscript.onload( 0, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\n\n\n\n\nvar // #5280: Internet Explorer will keep connections alive if we don't abort on unload\n\txhrOnUnloadAbort = window.ActiveXObject ? function() {\n\t\t// Abort all pending requests\n\t\tfor ( var key in xhrCallbacks ) {\n\t\t\txhrCallbacks[ key ]( 0, 1 );\n\t\t}\n\t} : false,\n\txhrId = 0,\n\txhrCallbacks;\n\n// Functions to create xhrs\nfunction createStandardXHR() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch( e ) {}\n}\n\nfunction createActiveXHR() {\n\ttry {\n\t\treturn new window.ActiveXObject( \"Microsoft.XMLHTTP\" );\n\t} catch( e ) {}\n}\n\n// Create the request object\n// (This is still attached to ajaxSettings for backward compatibility)\njQuery.ajaxSettings.xhr = window.ActiveXObject ?\n\t/* Microsoft failed to properly\n\t * implement the XMLHttpRequest in IE7 (can't request local files),\n\t * so we use the ActiveXObject when it is available\n\t * Additionally XMLHttpRequest can be disabled in IE7/IE8 so\n\t * we need a fallback.\n\t */\n\tfunction() {\n\t\treturn !this.isLocal && createStandardXHR() || createActiveXHR();\n\t} :\n\t// For all other browsers, use the standard XMLHttpRequest object\n\tcreateStandardXHR;\n\n// Determine support properties\n(function( xhr ) {\n\tjQuery.extend( jQuery.support, {\n\t\tajax: !!xhr,\n\t\tcors: !!xhr && ( \"withCredentials\" in xhr )\n\t});\n})( jQuery.ajaxSettings.xhr() );\n\n// Create transport if the browser can provide an xhr\nif ( jQuery.support.ajax ) {\n\n\tjQuery.ajaxTransport(function( s ) {\n\t\t// Cross domain only allowed if supported through XMLHttpRequest\n\t\tif ( !s.crossDomain || jQuery.support.cors ) {\n\n\t\t\tvar callback;\n\n\t\t\treturn {\n\t\t\t\tsend: function( headers, complete ) {\n\n\t\t\t\t\t// Get a new xhr\n\t\t\t\t\tvar xhr = s.xhr(),\n\t\t\t\t\t\thandle,\n\t\t\t\t\t\ti;\n\n\t\t\t\t\t// Open the socket\n\t\t\t\t\t// Passing null username, generates a login popup on Opera (#2865)\n\t\t\t\t\tif ( s.username ) {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async, s.username, s.password );\n\t\t\t\t\t} else {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply custom fields if provided\n\t\t\t\t\tif ( s.xhrFields ) {\n\t\t\t\t\t\tfor ( i in s.xhrFields ) {\n\t\t\t\t\t\t\txhr[ i ] = s.xhrFields[ i ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Override mime type if needed\n\t\t\t\t\tif ( s.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\t\txhr.overrideMimeType( s.mimeType );\n\t\t\t\t\t}\n\n\t\t\t\t\t// X-Requested-With header\n\t\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\t\tif ( !s.crossDomain && !headers[\"X-Requested-With\"] ) {\n\t\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t\t}\n\n\t\t\t\t\t// Need an extra try/catch for cross domain requests in Firefox 3\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch( _ ) {}\n\n\t\t\t\t\t// Do send the request\n\t\t\t\t\t// This may raise an exception which is actually\n\t\t\t\t\t// handled in jQuery.ajax (so no try/catch here)\n\t\t\t\t\txhr.send( ( s.hasContent && s.data ) || null );\n\n\t\t\t\t\t// Listener\n\t\t\t\t\tcallback = function( _, isAbort ) {\n\n\t\t\t\t\t\tvar status,\n\t\t\t\t\t\t\tstatusText,\n\t\t\t\t\t\t\tresponseHeaders,\n\t\t\t\t\t\t\tresponses,\n\t\t\t\t\t\t\txml;\n\n\t\t\t\t\t\t// Firefox throws exceptions when accessing properties\n\t\t\t\t\t\t// of an xhr when a network error occured\n\t\t\t\t\t\t// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)\n\t\t\t\t\t\ttry {\n\n\t\t\t\t\t\t\t// Was never called and is aborted or complete\n\t\t\t\t\t\t\tif ( callback && ( isAbort || xhr.readyState === 4 ) ) {\n\n\t\t\t\t\t\t\t\t// Only called once\n\t\t\t\t\t\t\t\tcallback = undefined;\n\n\t\t\t\t\t\t\t\t// Do not keep as active anymore\n\t\t\t\t\t\t\t\tif ( handle ) {\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = jQuery.noop;\n\t\t\t\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t\t\t\tdelete xhrCallbacks[ handle ];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// If it's an abort\n\t\t\t\t\t\t\t\tif ( isAbort ) {\n\t\t\t\t\t\t\t\t\t// Abort it manually if needed\n\t\t\t\t\t\t\t\t\tif ( xhr.readyState !== 4 ) {\n\t\t\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tstatus = xhr.status;\n\t\t\t\t\t\t\t\t\tresponseHeaders = xhr.getAllResponseHeaders();\n\t\t\t\t\t\t\t\t\tresponses = {};\n\t\t\t\t\t\t\t\t\txml = xhr.responseXML;\n\n\t\t\t\t\t\t\t\t\t// Construct response list\n\t\t\t\t\t\t\t\t\tif ( xml && xml.documentElement /* #4958 */ ) {\n\t\t\t\t\t\t\t\t\t\tresponses.xml = xml;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// When requesting binary data, IE6-9 will throw an exception\n\t\t\t\t\t\t\t\t\t// on any attempt to access responseText (#11426)\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tresponses.text = xhr.responseText;\n\t\t\t\t\t\t\t\t\t} catch( _ ) {\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Firefox throws an exception when accessing\n\t\t\t\t\t\t\t\t\t// statusText for faulty cross-domain requests\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tstatusText = xhr.statusText;\n\t\t\t\t\t\t\t\t\t} catch( e ) {\n\t\t\t\t\t\t\t\t\t\t// We normalize with Webkit giving an empty statusText\n\t\t\t\t\t\t\t\t\t\tstatusText = \"\";\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Filter status for non standard behaviors\n\n\t\t\t\t\t\t\t\t\t// If the request is local and we have data: assume a success\n\t\t\t\t\t\t\t\t\t// (success with no data won't get notified, that's the best we\n\t\t\t\t\t\t\t\t\t// can do given current implementations)\n\t\t\t\t\t\t\t\t\tif ( !status && s.isLocal && !s.crossDomain ) {\n\t\t\t\t\t\t\t\t\t\tstatus = responses.text ? 200 : 404;\n\t\t\t\t\t\t\t\t\t// IE - #1450: sometimes returns 1223 when it should be 204\n\t\t\t\t\t\t\t\t\t} else if ( status === 1223 ) {\n\t\t\t\t\t\t\t\t\t\tstatus = 204;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch( firefoxAccessException ) {\n\t\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\t\tcomplete( -1, firefoxAccessException );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Call complete if needed\n\t\t\t\t\t\tif ( responses ) {\n\t\t\t\t\t\t\tcomplete( status, statusText, responses, responseHeaders );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\t// if we're in sync mode or it's in cache\n\t\t\t\t\t// and has been retrieved directly (IE6 & IE7)\n\t\t\t\t\t// we need to manually fire the callback\n\t\t\t\t\tif ( !s.async || xhr.readyState === 4 ) {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t} else {\n\t\t\t\t\t\thandle = ++xhrId;\n\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t// Create the active xhrs callbacks list if needed\n\t\t\t\t\t\t\t// and attach the unload handler\n\t\t\t\t\t\t\tif ( !xhrCallbacks ) {\n\t\t\t\t\t\t\t\txhrCallbacks = {};\n\t\t\t\t\t\t\t\tjQuery( window ).unload( xhrOnUnloadAbort );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Add to list of active xhrs callbacks\n\t\t\t\t\t\t\txhrCallbacks[ handle ] = callback;\n\t\t\t\t\t\t}\n\t\t\t\t\t\txhr.onreadystatechange = callback;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tabort: function() {\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tcallback(0,1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t});\n}\n\n\n\n\nvar elemdisplay = {},\n\tiframe, iframeDoc,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trfxnum = /^([+\\-]=)?([\\d+.\\-]+)([a-z%]*)$/i,\n\ttimerId,\n\tfxAttrs = [\n\t\t// height animations\n\t\t[ \"height\", \"marginTop\", \"marginBottom\", \"paddingTop\", \"paddingBottom\" ],\n\t\t// width animations\n\t\t[ \"width\", \"marginLeft\", \"marginRight\", \"paddingLeft\", \"paddingRight\" ],\n\t\t// opacity animations\n\t\t[ \"opacity\" ]\n\t],\n\tfxNow;\n\njQuery.fn.extend({\n\tshow: function( speed, easing, callback ) {\n\t\tvar elem, display;\n\n\t\tif ( speed || speed === 0 ) {\n\t\t\treturn this.animate( genFx(\"show\", 3), speed, easing, callback );\n\n\t\t} else {\n\t\t\tfor ( var i = 0, j = this.length; i < j; i++ ) {\n\t\t\t\telem = this[ i ];\n\n\t\t\t\tif ( elem.style ) {\n\t\t\t\t\tdisplay = elem.style.display;\n\n\t\t\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t\t\t// being hidden by cascaded rules or not\n\t\t\t\t\tif ( !jQuery._data(elem, \"olddisplay\") && display === \"none\" ) {\n\t\t\t\t\t\tdisplay = elem.style.display = \"\";\n\t\t\t\t\t}\n\n\t\t\t\t\t// Set elements which have been overridden with display: none\n\t\t\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t\t\t// for such an element\n\t\t\t\t\tif ( (display === \"\" && jQuery.css(elem, \"display\") === \"none\") ||\n\t\t\t\t\t\t!jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {\n\t\t\t\t\t\tjQuery._data( elem, \"olddisplay\", defaultDisplay(elem.nodeName) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the display of most of the elements in a second loop\n\t\t\t// to avoid the constant reflow\n\t\t\tfor ( i = 0; i < j; i++ ) {\n\t\t\t\telem = this[ i ];\n\n\t\t\t\tif ( elem.style ) {\n\t\t\t\t\tdisplay = elem.style.display;\n\n\t\t\t\t\tif ( display === \"\" || display === \"none\" ) {\n\t\t\t\t\t\telem.style.display = jQuery._data( elem, \"olddisplay\" ) || \"\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\thide: function( speed, easing, callback ) {\n\t\tif ( speed || speed === 0 ) {\n\t\t\treturn this.animate( genFx(\"hide\", 3), speed, easing, callback);\n\n\t\t} else {\n\t\t\tvar elem, display,\n\t\t\t\ti = 0,\n\t\t\t\tj = this.length;\n\n\t\t\tfor ( ; i < j; i++ ) {\n\t\t\t\telem = this[i];\n\t\t\t\tif ( elem.style ) {\n\t\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\n\t\t\t\t\tif ( display !== \"none\" && !jQuery._data( elem, \"olddisplay\" ) ) {\n\t\t\t\t\t\tjQuery._data( elem, \"olddisplay\", display );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the display of the elements in a second loop\n\t\t\t// to avoid the constant reflow\n\t\t\tfor ( i = 0; i < j; i++ ) {\n\t\t\t\tif ( this[i].style ) {\n\t\t\t\t\tthis[i].style.display = \"none\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\t// Save the old toggle function\n\t_toggle: jQuery.fn.toggle,\n\n\ttoggle: function( fn, fn2, callback ) {\n\t\tvar bool = typeof fn === \"boolean\";\n\n\t\tif ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {\n\t\t\tthis._toggle.apply( this, arguments );\n\n\t\t} else if ( fn == null || bool ) {\n\t\t\tthis.each(function() {\n\t\t\t\tvar state = bool ? fn : jQuery(this).is(\":hidden\");\n\t\t\t\tjQuery(this)[ state ? \"show\" : \"hide\" ]();\n\t\t\t});\n\n\t\t} else {\n\t\t\tthis.animate(genFx(\"toggle\", 3), fn, fn2, callback);\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tfadeTo: function( speed, to, easing, callback ) {\n\t\treturn this.filter(\":hidden\").css(\"opacity\", 0).show().end()\n\t\t\t\t\t.animate({opacity: to}, speed, easing, callback);\n\t},\n\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar optall = jQuery.speed( speed, easing, callback );\n\n\t\tif ( jQuery.isEmptyObject( prop ) ) {\n\t\t\treturn this.each( optall.complete, [ false ] );\n\t\t}\n\n\t\t// Do not change referenced properties as per-property easing will be lost\n\t\tprop = jQuery.extend( {}, prop );\n\n\t\tfunction doAnimation() {\n\t\t\t// XXX 'this' does not always have a nodeName when running the\n\t\t\t// test suite\n\n\t\t\tif ( optall.queue === false ) {\n\t\t\t\tjQuery._mark( this );\n\t\t\t}\n\n\t\t\tvar opt = jQuery.extend( {}, optall ),\n\t\t\t\tisElement = this.nodeType === 1,\n\t\t\t\thidden = isElement && jQuery(this).is(\":hidden\"),\n\t\t\t\tname, val, p, e, hooks, replace,\n\t\t\t\tparts, start, end, unit,\n\t\t\t\tmethod;\n\n\t\t\t// will store per property easing and be used to determine when an animation is complete\n\t\t\topt.animatedProperties = {};\n\n\t\t\t// first pass over propertys to expand / normalize\n\t\t\tfor ( p in prop ) {\n\t\t\t\tname = jQuery.camelCase( p );\n\t\t\t\tif ( p !== name ) {\n\t\t\t\t\tprop[ name ] = prop[ p ];\n\t\t\t\t\tdelete prop[ p ];\n\t\t\t\t}\n\n\t\t\t\tif ( ( hooks = jQuery.cssHooks[ name ] ) && \"expand\" in hooks ) {\n\t\t\t\t\treplace = hooks.expand( prop[ name ] );\n\t\t\t\t\tdelete prop[ name ];\n\n\t\t\t\t\t// not quite $.extend, this wont overwrite keys already present.\n\t\t\t\t\t// also - reusing 'p' from above because we have the correct \"name\"\n\t\t\t\t\tfor ( p in replace ) {\n\t\t\t\t\t\tif ( ! ( p in prop ) ) {\n\t\t\t\t\t\t\tprop[ p ] = replace[ p ];\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\tfor ( name in prop ) {\n\t\t\t\tval = prop[ name ];\n\t\t\t\t// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)\n\t\t\t\tif ( jQuery.isArray( val ) ) {\n\t\t\t\t\topt.animatedProperties[ name ] = val[ 1 ];\n\t\t\t\t\tval = prop[ name ] = val[ 0 ];\n\t\t\t\t} else {\n\t\t\t\t\topt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';\n\t\t\t\t}\n\n\t\t\t\tif ( val === \"hide\" && hidden || val === \"show\" && !hidden ) {\n\t\t\t\t\treturn opt.complete.call( this );\n\t\t\t\t}\n\n\t\t\t\tif ( isElement && ( name === \"height\" || name === \"width\" ) ) {\n\t\t\t\t\t// Make sure that nothing sneaks out\n\t\t\t\t\t// Record all 3 overflow attributes because IE does not\n\t\t\t\t\t// change the overflow attribute when overflowX and\n\t\t\t\t\t// overflowY are set to the same value\n\t\t\t\t\topt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];\n\n\t\t\t\t\t// Set display property to inline-block for height/width\n\t\t\t\t\t// animations on inline elements that are having width/height animated\n\t\t\t\t\tif ( jQuery.css( this, \"display\" ) === \"inline\" &&\n\t\t\t\t\t\t\tjQuery.css( this, \"float\" ) === \"none\" ) {\n\n\t\t\t\t\t\t// inline-level elements accept inline-block;\n\t\t\t\t\t\t// block-level elements need to be inline with layout\n\t\t\t\t\t\tif ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === \"inline\" ) {\n\t\t\t\t\t\t\tthis.style.display = \"inline-block\";\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.style.zoom = 1;\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\tif ( opt.overflow != null ) {\n\t\t\t\tthis.style.overflow = \"hidden\";\n\t\t\t}\n\n\t\t\tfor ( p in prop ) {\n\t\t\t\te = new jQuery.fx( this, opt, p );\n\t\t\t\tval = prop[ p ];\n\n\t\t\t\tif ( rfxtypes.test( val ) ) {\n\n\t\t\t\t\t// Tracks whether to show or hide based on private\n\t\t\t\t\t// data attached to the element\n\t\t\t\t\tmethod = jQuery._data( this, \"toggle\" + p ) || ( val === \"toggle\" ? hidden ? \"show\" : \"hide\" : 0 );\n\t\t\t\t\tif ( method ) {\n\t\t\t\t\t\tjQuery._data( this, \"toggle\" + p, method === \"show\" ? \"hide\" : \"show\" );\n\t\t\t\t\t\te[ method ]();\n\t\t\t\t\t} else {\n\t\t\t\t\t\te[ val ]();\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\t\t\t\t\tparts = rfxnum.exec( val );\n\t\t\t\t\tstart = e.cur();\n\n\t\t\t\t\tif ( parts ) {\n\t\t\t\t\t\tend = parseFloat( parts[2] );\n\t\t\t\t\t\tunit = parts[3] || ( jQuery.cssNumber[ p ] ? \"\" : \"px\" );\n\n\t\t\t\t\t\t// We need to compute starting value\n\t\t\t\t\t\tif ( unit !== \"px\" ) {\n\t\t\t\t\t\t\tjQuery.style( this, p, (end || 1) + unit);\n\t\t\t\t\t\t\tstart = ( (end || 1) / e.cur() ) * start;\n\t\t\t\t\t\t\tjQuery.style( this, p, start + unit);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\t\t\tif ( parts[1] ) {\n\t\t\t\t\t\t\tend = ( (parts[ 1 ] === \"-=\" ? -1 : 1) * end ) + start;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\te.custom( start, end, unit );\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\te.custom( start, val, \"\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// For JS strict compliance\n\t\t\treturn true;\n\t\t}\n\n\t\treturn optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar index,\n\t\t\t\thadTimers = false,\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = jQuery._data( this );\n\n\t\t\t// clear marker counters if we know they won't be\n\t\t\tif ( !gotoEnd ) {\n\t\t\t\tjQuery._unmark( true, this );\n\t\t\t}\n\n\t\t\tfunction stopQueue( elem, data, index ) {\n\t\t\t\tvar hooks = data[ index ];\n\t\t\t\tjQuery.removeData( elem, index, true );\n\t\t\t\thooks.stop( gotoEnd );\n\t\t\t}\n\n\t\t\tif ( type == null ) {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && index.indexOf(\".run\") === index.length - 4 ) {\n\t\t\t\t\t\tstopQueue( this, data, index );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if ( data[ index = type + \".run\" ] && data[ index ].stop ){\n\t\t\t\tstopQueue( this, data, index );\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {\n\t\t\t\t\tif ( gotoEnd ) {\n\n\t\t\t\t\t\t// force the next step to be the last\n\t\t\t\t\t\ttimers[ index ]( true );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttimers[ index ].saveState();\n\t\t\t\t\t}\n\t\t\t\t\thadTimers = true;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// start the next in the queue if the last step wasn't forced\n\t\t\t// timers currently will call their complete callbacks, which will dequeue\n\t\t\t// but only if they were gotoEnd\n\t\t\tif ( !( gotoEnd && hadTimers ) ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t});\n\t}\n\n});\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\tsetTimeout( clearFxNow, 0 );\n\treturn ( fxNow = jQuery.now() );\n}\n\nfunction clearFxNow() {\n\tfxNow = undefined;\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, num ) {\n\tvar obj = {};\n\n\tjQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {\n\t\tobj[ this ] = type;\n\t});\n\n\treturn obj;\n}\n\n// Generate shortcuts for custom animations\njQuery.each({\n\tslideDown: genFx( \"show\", 1 ),\n\tslideUp: genFx( \"hide\", 1 ),\n\tslideToggle: genFx( \"toggle\", 1 ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n});\n\njQuery.extend({\n\tspeed: function( speed, easing, fn ) {\n\t\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\t\tcomplete: fn || !fn && easing ||\n\t\t\t\tjQuery.isFunction( speed ) && speed,\n\t\t\tduration: speed,\n\t\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t\t};\n\n\t\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n\t\t\topt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n\t\t// normalize opt.queue - true/undefined/null -> \"fx\"\n\t\tif ( opt.queue == null || opt.queue === true ) {\n\t\t\topt.queue = \"fx\";\n\t\t}\n\n\t\t// Queueing\n\t\topt.old = opt.complete;\n\n\t\topt.complete = function( noUnmark ) {\n\t\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\t\topt.old.call( this );\n\t\t\t}\n\n\t\t\tif ( opt.queue ) {\n\t\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t\t} else if ( noUnmark !== false ) {\n\t\t\t\tjQuery._unmark( this );\n\t\t\t}\n\t\t};\n\n\t\treturn opt;\n\t},\n\n\teasing: {\n\t\tlinear: function( p ) {\n\t\t\treturn p;\n\t\t},\n\t\tswing: function( p ) {\n\t\t\treturn ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;\n\t\t}\n\t},\n\n\ttimers: [],\n\n\tfx: function( elem, options, prop ) {\n\t\tthis.options = options;\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\n\t\toptions.orig = options.orig || {};\n\t}\n\n});\n\njQuery.fx.prototype = {\n\t// Simple function for setting a style value\n\tupdate: function() {\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\t( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );\n\t},\n\n\t// Get the current size\n\tcur: function() {\n\t\tif ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {\n\t\t\treturn this.elem[ this.prop ];\n\t\t}\n\n\t\tvar parsed,\n\t\t\tr = jQuery.css( this.elem, this.prop );\n\t\t// Empty strings, null, undefined and \"auto\" are converted to 0,\n\t\t// complex values such as \"rotate(1rad)\" are returned as is,\n\t\t// simple values such as \"10px\" are parsed to Float.\n\t\treturn isNaN( parsed = parseFloat( r ) ) ? !r || r === \"auto\" ? 0 : r : parsed;\n\t},\n\n\t// Start an animation from one number to another\n\tcustom: function( from, to, unit ) {\n\t\tvar self = this,\n\t\t\tfx = jQuery.fx;\n\n\t\tthis.startTime = fxNow || createFxNow();\n\t\tthis.end = to;\n\t\tthis.now = this.start = from;\n\t\tthis.pos = this.state = 0;\n\t\tthis.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? \"\" : \"px\" );\n\n\t\tfunction t( gotoEnd ) {\n\t\t\treturn self.step( gotoEnd );\n\t\t}\n\n\t\tt.queue = this.options.queue;\n\t\tt.elem = this.elem;\n\t\tt.saveState = function() {\n\t\t\tif ( jQuery._data( self.elem, \"fxshow\" + self.prop ) === undefined ) {\n\t\t\t\tif ( self.options.hide ) {\n\t\t\t\t\tjQuery._data( self.elem, \"fxshow\" + self.prop, self.start );\n\t\t\t\t} else if ( self.options.show ) {\n\t\t\t\t\tjQuery._data( self.elem, \"fxshow\" + self.prop, self.end );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tif ( t() && jQuery.timers.push(t) && !timerId ) {\n\t\t\ttimerId = setInterval( fx.tick, fx.interval );\n\t\t}\n\t},\n\n\t// Simple 'show' function\n\tshow: function() {\n\t\tvar dataShow = jQuery._data( this.elem, \"fxshow\" + this.prop );\n\n\t\t// Remember where we started, so that we can go back to it later\n\t\tthis.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );\n\t\tthis.options.show = true;\n\n\t\t// Begin the animation\n\t\t// Make sure that we start at a small width/height to avoid any flash of content\n\t\tif ( dataShow !== undefined ) {\n\t\t\t// This show is picking up where a previous hide or show left off\n\t\t\tthis.custom( this.cur(), dataShow );\n\t\t} else {\n\t\t\tthis.custom( this.prop === \"width\" || this.prop === \"height\" ? 1 : 0, this.cur() );\n\t\t}\n\n\t\t// Start by showing the element\n\t\tjQuery( this.elem ).show();\n\t},\n\n\t// Simple 'hide' function\n\thide: function() {\n\t\t// Remember where we started, so that we can go back to it later\n\t\tthis.options.orig[ this.prop ] = jQuery._data( this.elem, \"fxshow\" + this.prop ) || jQuery.style( this.elem, this.prop );\n\t\tthis.options.hide = true;\n\n\t\t// Begin the animation\n\t\tthis.custom( this.cur(), 0 );\n\t},\n\n\t// Each step of an animation\n\tstep: function( gotoEnd ) {\n\t\tvar p, n, complete,\n\t\t\tt = fxNow || createFxNow(),\n\t\t\tdone = true,\n\t\t\telem = this.elem,\n\t\t\toptions = this.options;\n\n\t\tif ( gotoEnd || t >= options.duration + this.startTime ) {\n\t\t\tthis.now = this.end;\n\t\t\tthis.pos = this.state = 1;\n\t\t\tthis.update();\n\n\t\t\toptions.animatedProperties[ this.prop ] = true;\n\n\t\t\tfor ( p in options.animatedProperties ) {\n\t\t\t\tif ( options.animatedProperties[ p ] !== true ) {\n\t\t\t\t\tdone = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( done ) {\n\t\t\t\t// Reset the overflow\n\t\t\t\tif ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {\n\n\t\t\t\t\tjQuery.each( [ \"\", \"X\", \"Y\" ], function( index, value ) {\n\t\t\t\t\t\telem.style[ \"overflow\" + value ] = options.overflow[ index ];\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Hide the element if the \"hide\" operation was done\n\t\t\t\tif ( options.hide ) {\n\t\t\t\t\tjQuery( elem ).hide();\n\t\t\t\t}\n\n\t\t\t\t// Reset the properties, if the item has been hidden or shown\n\t\t\t\tif ( options.hide || options.show ) {\n\t\t\t\t\tfor ( p in options.animatedProperties ) {\n\t\t\t\t\t\tjQuery.style( elem, p, options.orig[ p ] );\n\t\t\t\t\t\tjQuery.removeData( elem, \"fxshow\" + p, true );\n\t\t\t\t\t\t// Toggle data is no longer needed\n\t\t\t\t\t\tjQuery.removeData( elem, \"toggle\" + p, true );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Execute the complete function\n\t\t\t\t// in the event that the complete function throws an exception\n\t\t\t\t// we must ensure it won't be called twice. #5684\n\n\t\t\t\tcomplete = options.complete;\n\t\t\t\tif ( complete ) {\n\n\t\t\t\t\toptions.complete = false;\n\t\t\t\t\tcomplete.call( elem );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t} else {\n\t\t\t// classical easing cannot be used with an Infinity duration\n\t\t\tif ( options.duration == Infinity ) {\n\t\t\t\tthis.now = t;\n\t\t\t} else {\n\t\t\t\tn = t - this.startTime;\n\t\t\t\tthis.state = n / options.duration;\n\n\t\t\t\t// Perform the easing function, defaults to swing\n\t\t\t\tthis.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );\n\t\t\t\tthis.now = this.start + ( (this.end - this.start) * this.pos );\n\t\t\t}\n\t\t\t// Perform the next step of the animation\n\t\t\tthis.update();\n\t\t}\n\n\t\treturn true;\n\t}\n};\n\njQuery.extend( jQuery.fx, {\n\ttick: function() {\n\t\tvar timer,\n\t\t\ttimers = jQuery.timers,\n\t\t\ti = 0;\n\n\t\tfor ( ; i < timers.length; i++ ) {\n\t\t\ttimer = timers[ i ];\n\t\t\t// Checks the timer has not already been removed\n\t\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\t\ttimers.splice( i--, 1 );\n\t\t\t}\n\t\t}\n\n\t\tif ( !timers.length ) {\n\t\t\tjQuery.fx.stop();\n\t\t}\n\t},\n\n\tinterval: 13,\n\n\tstop: function() {\n\t\tclearInterval( timerId );\n\t\ttimerId = null;\n\t},\n\n\tspeeds: {\n\t\tslow: 600,\n\t\tfast: 200,\n\t\t// Default speed\n\t\t_default: 400\n\t},\n\n\tstep: {\n\t\topacity: function( fx ) {\n\t\t\tjQuery.style( fx.elem, \"opacity\", fx.now );\n\t\t},\n\n\t\t_default: function( fx ) {\n\t\t\tif ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {\n\t\t\t\tfx.elem.style[ fx.prop ] = fx.now + fx.unit;\n\t\t\t} else {\n\t\t\t\tfx.elem[ fx.prop ] = fx.now;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Ensure props that can't be negative don't go there on undershoot easing\njQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {\n\t// exclude marginTop, marginLeft, marginBottom and marginRight from this list\n\tif ( prop.indexOf( \"margin\" ) ) {\n\t\tjQuery.fx.step[ prop ] = function( fx ) {\n\t\t\tjQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );\n\t\t};\n\t}\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.animated = function( elem ) {\n\t\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\t\treturn elem === fn.elem;\n\t\t}).length;\n\t};\n}\n\n// Try to restore the default display value of an element\nfunction defaultDisplay( nodeName ) {\n\n\tif ( !elemdisplay[ nodeName ] ) {\n\n\t\tvar body = document.body,\n\t\t\telem = jQuery( \"<\" + nodeName + \">\" ).appendTo( body ),\n\t\t\tdisplay = elem.css( \"display\" );\n\t\telem.remove();\n\n\t\t// If the simple way fails,\n\t\t// get element's real default display by attaching it to a temp iframe\n\t\tif ( display === \"none\" || display === \"\" ) {\n\t\t\t// No iframe to use yet, so create it\n\t\t\tif ( !iframe ) {\n\t\t\t\tiframe = document.createElement( \"iframe\" );\n\t\t\t\tiframe.frameBorder = iframe.width = iframe.height = 0;\n\t\t\t}\n\n\t\t\tbody.appendChild( iframe );\n\n\t\t\t// Create a cacheable copy of the iframe document on first call.\n\t\t\t// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML\n\t\t\t// document to it; WebKit & Firefox won't allow reusing the iframe document.\n\t\t\tif ( !iframeDoc || !iframe.createElement ) {\n\t\t\t\tiframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;\n\t\t\t\tiframeDoc.write( ( jQuery.support.boxModel ? \"<!doctype html>\" : \"\" ) + \"<html><body>\" );\n\t\t\t\tiframeDoc.close();\n\t\t\t}\n\n\t\t\telem = iframeDoc.createElement( nodeName );\n\n\t\t\tiframeDoc.body.appendChild( elem );\n\n\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\tbody.removeChild( iframe );\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn elemdisplay[ nodeName ];\n}\n\n\n\n\nvar getOffset,\n\trtable = /^t(?:able|d|h)$/i,\n\trroot = /^(?:body|html)$/i;\n\nif ( \"getBoundingClientRect\" in document.documentElement ) {\n\tgetOffset = function( elem, doc, docElem, box ) {\n\t\ttry {\n\t\t\tbox = elem.getBoundingClientRect();\n\t\t} catch(e) {}\n\n\t\t// Make sure we're not dealing with a disconnected DOM node\n\t\tif ( !box || !jQuery.contains( docElem, elem ) ) {\n\t\t\treturn box ? { top: box.top, left: box.left } : { top: 0, left: 0 };\n\t\t}\n\n\t\tvar body = doc.body,\n\t\t\twin = getWindow( doc ),\n\t\t\tclientTop  = docElem.clientTop  || body.clientTop  || 0,\n\t\t\tclientLeft = docElem.clientLeft || body.clientLeft || 0,\n\t\t\tscrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,\n\t\t\tscrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,\n\t\t\ttop  = box.top  + scrollTop  - clientTop,\n\t\t\tleft = box.left + scrollLeft - clientLeft;\n\n\t\treturn { top: top, left: left };\n\t};\n\n} else {\n\tgetOffset = function( elem, doc, docElem ) {\n\t\tvar computedStyle,\n\t\t\toffsetParent = elem.offsetParent,\n\t\t\tprevOffsetParent = elem,\n\t\t\tbody = doc.body,\n\t\t\tdefaultView = doc.defaultView,\n\t\t\tprevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,\n\t\t\ttop = elem.offsetTop,\n\t\t\tleft = elem.offsetLeft;\n\n\t\twhile ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {\n\t\t\tif ( jQuery.support.fixedPosition && prevComputedStyle.position === \"fixed\" ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcomputedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;\n\t\t\ttop  -= elem.scrollTop;\n\t\t\tleft -= elem.scrollLeft;\n\n\t\t\tif ( elem === offsetParent ) {\n\t\t\t\ttop  += elem.offsetTop;\n\t\t\t\tleft += elem.offsetLeft;\n\n\t\t\t\tif ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {\n\t\t\t\t\ttop  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n\t\t\t\t\tleft += parseFloat( computedStyle.borderLeftWidth ) || 0;\n\t\t\t\t}\n\n\t\t\t\tprevOffsetParent = offsetParent;\n\t\t\t\toffsetParent = elem.offsetParent;\n\t\t\t}\n\n\t\t\tif ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== \"visible\" ) {\n\t\t\t\ttop  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n\t\t\t\tleft += parseFloat( computedStyle.borderLeftWidth ) || 0;\n\t\t\t}\n\n\t\t\tprevComputedStyle = computedStyle;\n\t\t}\n\n\t\tif ( prevComputedStyle.position === \"relative\" || prevComputedStyle.position === \"static\" ) {\n\t\t\ttop  += body.offsetTop;\n\t\t\tleft += body.offsetLeft;\n\t\t}\n\n\t\tif ( jQuery.support.fixedPosition && prevComputedStyle.position === \"fixed\" ) {\n\t\t\ttop  += Math.max( docElem.scrollTop, body.scrollTop );\n\t\t\tleft += Math.max( docElem.scrollLeft, body.scrollLeft );\n\t\t}\n\n\t\treturn { top: top, left: left };\n\t};\n}\n\njQuery.fn.offset = function( options ) {\n\tif ( arguments.length ) {\n\t\treturn options === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function( i ) {\n\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t});\n\t}\n\n\tvar elem = this[0],\n\t\tdoc = elem && elem.ownerDocument;\n\n\tif ( !doc ) {\n\t\treturn null;\n\t}\n\n\tif ( elem === doc.body ) {\n\t\treturn jQuery.offset.bodyOffset( elem );\n\t}\n\n\treturn getOffset( elem, doc, doc.documentElement );\n};\n\njQuery.offset = {\n\n\tbodyOffset: function( body ) {\n\t\tvar top = body.offsetTop,\n\t\t\tleft = body.offsetLeft;\n\n\t\tif ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {\n\t\t\ttop  += parseFloat( jQuery.css(body, \"marginTop\") ) || 0;\n\t\t\tleft += parseFloat( jQuery.css(body, \"marginLeft\") ) || 0;\n\t\t}\n\n\t\treturn { top: top, left: left };\n\t},\n\n\tsetOffset: function( elem, options, i ) {\n\t\tvar position = jQuery.css( elem, \"position\" );\n\n\t\t// set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tvar curElem = jQuery( elem ),\n\t\t\tcurOffset = curElem.offset(),\n\t\t\tcurCSSTop = jQuery.css( elem, \"top\" ),\n\t\t\tcurCSSLeft = jQuery.css( elem, \"left\" ),\n\t\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) && jQuery.inArray(\"auto\", [curCSSTop, curCSSLeft]) > -1,\n\t\t\tprops = {}, curPosition = {}, curTop, curLeft;\n\n\t\t// need to be able to calculate position if either top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\t\t\toptions = options.call( elem, i, curOffset );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\n\njQuery.fn.extend({\n\n\tposition: function() {\n\t\tif ( !this[0] ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar elem = this[0],\n\n\t\t// Get *real* offsetParent\n\t\toffsetParent = this.offsetParent(),\n\n\t\t// Get correct offsets\n\t\toffset       = this.offset(),\n\t\tparentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();\n\n\t\t// Subtract element margins\n\t\t// note: when an element has margin: auto the offsetLeft and marginLeft\n\t\t// are the same in Safari causing offset.left to incorrectly be 0\n\t\toffset.top  -= parseFloat( jQuery.css(elem, \"marginTop\") ) || 0;\n\t\toffset.left -= parseFloat( jQuery.css(elem, \"marginLeft\") ) || 0;\n\n\t\t// Add offsetParent borders\n\t\tparentOffset.top  += parseFloat( jQuery.css(offsetParent[0], \"borderTopWidth\") ) || 0;\n\t\tparentOffset.left += parseFloat( jQuery.css(offsetParent[0], \"borderLeftWidth\") ) || 0;\n\n\t\t// Subtract the two offsets\n\t\treturn {\n\t\t\ttop:  offset.top  - parentOffset.top,\n\t\t\tleft: offset.left - parentOffset.left\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || document.body;\n\t\t\twhile ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, \"position\") === \"static\") ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\t\t\treturn offsetParent;\n\t\t});\n\t}\n});\n\n\n// Create scrollLeft and scrollTop methods\njQuery.each( {scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\"}, function( method, prop ) {\n\tvar top = /Y/.test( prop );\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn jQuery.access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? (prop in win) ? win[ prop ] :\n\t\t\t\t\tjQuery.support.boxModel && win.document.documentElement[ method ] ||\n\t\t\t\t\t\twin.document.body[ method ] :\n\t\t\t\t\telem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : jQuery( win ).scrollLeft(),\n\t\t\t\t\t top ? val : jQuery( win ).scrollTop()\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length, null );\n\t};\n});\n\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ?\n\t\telem :\n\t\telem.nodeType === 9 ?\n\t\t\telem.defaultView || elem.parentWindow :\n\t\t\tfalse;\n}\n\n\n\n\n// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tvar clientProp = \"client\" + name,\n\t\tscrollProp = \"scroll\" + name,\n\t\toffsetProp = \"offset\" + name;\n\n\t// innerHeight and innerWidth\n\tjQuery.fn[ \"inner\" + name ] = function() {\n\t\tvar elem = this[0];\n\t\treturn elem ?\n\t\t\telem.style ?\n\t\t\tparseFloat( jQuery.css( elem, type, \"padding\" ) ) :\n\t\t\tthis[ type ]() :\n\t\t\tnull;\n\t};\n\n\t// outerHeight and outerWidth\n\tjQuery.fn[ \"outer\" + name ] = function( margin ) {\n\t\tvar elem = this[0];\n\t\treturn elem ?\n\t\t\telem.style ?\n\t\t\tparseFloat( jQuery.css( elem, type, margin ? \"margin\" : \"border\" ) ) :\n\t\t\tthis[ type ]() :\n\t\t\tnull;\n\t};\n\n\tjQuery.fn[ type ] = function( value ) {\n\t\treturn jQuery.access( this, function( elem, type, value ) {\n\t\t\tvar doc, docElemProp, orig, ret;\n\n\t\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t\t// 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat\n\t\t\t\tdoc = elem.document;\n\t\t\t\tdocElemProp = doc.documentElement[ clientProp ];\n\t\t\t\treturn jQuery.support.boxModel && docElemProp ||\n\t\t\t\t\tdoc.body && doc.body[ clientProp ] || docElemProp;\n\t\t\t}\n\n\t\t\t// Get document width or height\n\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height], whichever is greater\n\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t// when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]\n\t\t\t\t// so we can't use max, as it'll choose the incorrect offset[Width/Height]\n\t\t\t\t// instead we use the correct client[Width/Height]\n\t\t\t\t// support:IE6\n\t\t\t\tif ( doc[ clientProp ] >= doc[ scrollProp ] ) {\n\t\t\t\t\treturn doc[ clientProp ];\n\t\t\t\t}\n\n\t\t\t\treturn Math.max(\n\t\t\t\t\telem.body[ scrollProp ], doc[ scrollProp ],\n\t\t\t\t\telem.body[ offsetProp ], doc[ offsetProp ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Get width or height on the element\n\t\t\tif ( value === undefined ) {\n\t\t\t\torig = jQuery.css( elem, type );\n\t\t\t\tret = parseFloat( orig );\n\t\t\t\treturn jQuery.isNumeric( ret ) ? ret : orig;\n\t\t\t}\n\n\t\t\t// Set the width or height on the element\n\t\t\tjQuery( elem ).css( type, value );\n\t\t}, type, value, arguments.length, null );\n\t};\n});\n\n\n\n\n// Expose for component\nmodule.exports = jQuery;\n\n// Expose jQuery to the global object\n// window.jQuery = window.$ = jQuery;\n\n// Expose jQuery as an AMD module, but only for AMD loaders that\n// understand the issues with loading multiple versions of jQuery\n// in a page that all might call define(). The loader will indicate\n// they have special allowances for multiple jQuery versions by\n// specifying define.amd.jQuery = true. Register as a named module,\n// since jQuery can be concatenated with other files that may use define,\n// but not use a proper concatenation script that understands anonymous\n// AMD modules. A named AMD is safest and most robust way to register.\n// Lowercase jquery is used because AMD module names are derived from\n// file names, and jQuery is normally delivered in a lowercase file name.\n// Do this after creating the global so that if an AMD module wants to call\n// noConflict to hide this version of jQuery, it will work.\nif ( typeof define === \"function\" && define.amd && define.amd.jQuery ) {\n\tdefine( \"jquery\", [], function () { return jQuery; } );\n}\n\n\n\n})( window );\n\n});\nrequire.register(\"filter/index.js\", function(exports, require, module){\n// Dependencies\nvar $ = require('jquery');\n\n// Expose `Filter`.\nmodule.exports = Filter;\n\n// Case-insensitive contains()\n$.expr[':'].Contains = function(a,i,m){\n    return (a.textContent || a.innerText || '').toUpperCase().indexOf(m[3].toUpperCase())>=0;\n};\n\n/**\n * Initialize a filterable list.\n */\nfunction Filter(list) {\n    this.el = list;\n    \n    // Filter input\n    var form = $('<form>').attr({ 'action':'#' });\n    var input = $('<input>').attr({ 'type':'text', 'placeholder':'Filter by keyword' });\n    $(form).append(input).prependTo(this.el);\n    \n    // Filter function\n    var self = this;\n    $(input).change(function () {\n        var filter = $(this).val();\n        if(filter) {\n            $(self.el).find('a:not(:Contains(' + filter + '))').parent().hide();\n            $(self.el).find('a:Contains(' + filter + ')').parent().show();\n        } else {\n            $(self.el).find('li').show();\n        }\n        \n        // Hide titles when group is empty\n        $(self.el).find('ul').each(function () {\n            if (!$(this).find('li:visible').length) {\n                $(this).prev('h2').hide();\n            } else {\n                $(this).prev('h2').show();\n            }\n        });\n\n        return false;\n    })\n    .keyup( function () { $(this).change(); });\n    \n    return this;\n}\n});\nrequire.register(\"boot/index.js\", function(exports, require, module){\nvar $ = require('jquery'),\n    Filter = require('filter');\n\n// Collapsible articles\n$('article').each(function () {\n    var that = $(this);\n    var header = that.children('a');\n    var body = that.children('.body');\n    body.hide();\n    header.toggle(\n        function () { body.slideDown('fast'); that.addClass('active'); },\n        function () { body.slideUp('fast'); that.removeClass('active'); }\n    );\n});\n\nvar anchor = window.location.hash.substring(1);\nif (anchor) $('article a[name=\"' + anchor + '\"]').trigger('click');\n\n// Expanding the article on link click and scrolling down to it\n$('#sidebar a').each(function () {\n    var that = $(this);\n    var id = that.attr('href').substring(1);\n    that.click(function (e) {\n        var header = $('article a[name=\"'+ id +'\"]')\n        if (!header.parent().hasClass('active')) header.trigger('click');\n        $('html, body').animate({ scrollTop: header.offset().top }, 'fast');\n    });\n\n    // If we find a link in the body with similar anchor, add the same behavior\n    $('.body a[href=\"#'+ id +'\"]').click(function (e) {\n        $('#sidebar a[href=\"#'+ id +'\"]').trigger('click');\n    });\n});\n\n// Hide all/Show all links\nvar show = $('<a class=\\'control show\\'>Show all</a>');\nshow.click(function () {\n  $('#content article:not(\".active\") > a').trigger('click');    \n});\n$('#content').prepend(show);\n\nvar hide = $('<a class=\\'control hide\\'>Hide all</a>');\nhide.click(function () {\n  $('#content article.active > a').trigger('click');    \n});\n$('#content').prepend(hide);\n\n// Making our navigation sticky\nnew Filter($('#sidebar > ul'));\n});\nrequire.alias(\"boot/index.js\", \"carte/deps/boot/index.js\");\n\nrequire.alias(\"component-jquery/index.js\", \"boot/deps/jquery/index.js\");\n\nrequire.alias(\"filter/index.js\", \"boot/deps/filter/index.js\");\nrequire.alias(\"component-jquery/index.js\", \"filter/deps/jquery/index.js\");\n\n"
  },
  {
    "path": "docs/doc/admin.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n    \n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n    \n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n         \n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n        \n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n            \n        \n    </div>\n    \n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n                \n                    <p>Production : <strong>/api/v1</strong></p>\n                \n                    <p>Staging : <strong>/api/v1</strong></p>\n                \n              </div>\n            </div>    \n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n            \n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/admin/login</a></li>\n            \n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/admin/change_user_role</a></li>\n            \n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/admin/change_user_passwd</a></li>\n            \n                <li role=\"presentation\"><a href=\"#3top\" role=\"tab\" data-toggle=\"tab\">DELETE : /api/v1/admin/delete_user</a></li>\n            \n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n        \n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;sig&#34;: &#34;25ae3f6cdb1711e79997005056a6aba2&#34;, &#34;name&#34;: &#34;root&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/x-www-form-urlencoded\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Post Form </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>name</td>\n                        <td> qfeng</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">{&#34;sig&#34;:&#34;05434ff8db0311e7afde005056a6aba2&#34;,&#34;name&#34;:&#34;qfeng&#34;,&#34;admin&#34;:true}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"sig\\\":\\\"05434ff8db0311e7afde005056a6aba2\\\",\\\"name\\\":\\\"qfeng\\\",\\\"admin\\\":true}\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;sig&#34;: &#34;25ae3f6cdb1711e79997005056a6aba2&#34;, &#34;name&#34;: &#34;root&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/x-www-form-urlencoded\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Post Form </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>name</td>\n                        <td> daye</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">400</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-1\">{&#34;error&#34;:&#34;no such user&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"no such user\\\"}\");\n                            document.getElementById('response-body-0-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;sig&#34;: &#34;05434ff8db0311e7afde005056a6aba2&#34;, &#34;name&#34;: &#34;qfeng&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/x-www-form-urlencoded\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Post Form </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>name</td>\n                        <td> qfeng</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">400</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-2\">{&#34;error&#34;:&#34;API_USER not admin, no permissions can do this&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"API_USER not admin, no permissions can do this\\\"}\");\n                            document.getElementById('response-body-0-2').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;sig&#34;: &#34;25ae3f6cdb1711e79997005056a6aba2&#34;, &#34;name&#34;: &#34;root&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-1-0\" class=\"prettyprint\">{&#34;admin&#34;: &#34;yes&#34;, &#34;user_id&#34;: 12}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"admin\\\": \\\"yes\\\", \\\"user_id\\\": 12}\");\n                            document.getElementById('request-body1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">{&#34;message&#34;:&#34;user role update sccuessful, affect row: 0&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"user role update sccuessful, affect row: 0\\\"}\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;sig&#34;: &#34;25ae3f6cdb1711e79997005056a6aba2&#34;, &#34;name&#34;: &#34;root&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-1-1\" class=\"prettyprint\">{&#34;admin&#34;: &#34;no&#34;, &#34;user_id&#34;: 12}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"admin\\\": \\\"no\\\", \\\"user_id\\\": 12}\");\n                            document.getElementById('request-body1-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-1\">{&#34;message&#34;:&#34;user role update sccuessful, affect row: 1&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"user role update sccuessful, affect row: 1\\\"}\");\n                            document.getElementById('response-body-1-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;sig&#34;: &#34;25ae3f6cdb1711e79997005056a6aba2&#34;, &#34;name&#34;: &#34;root&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-0\" class=\"prettyprint\">{&#34;password&#34;: &#34;lalala&#34;, &#34;user_id&#34;: 12}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"password\\\": \\\"lalala\\\", \\\"user_id\\\": 12}\");\n                            document.getElementById('request-body2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">{&#34;message&#34;:&#34;password updated!&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"password updated!\\\"}\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"3top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;sig&#34;: &#34;25ae3f6cdb1711e79997005056a6aba2&#34;, &#34;name&#34;: &#34;root&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-3-0\" class=\"prettyprint\">{&#34;user_id&#34;: 12}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"user_id\\\": 12}\");\n                            document.getElementById('request-body3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-3-0\">{&#34;message&#34;:&#34;user 12 has been delete, affect row: 1&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"user 12 has been delete, affect row: 1\\\"}\");\n                            document.getElementById('response-body-3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>"
  },
  {
    "path": "docs/doc/admin.html.json",
    "content": "{\n    \"ApiSpecs\": [\n        {\n            \"HttpVerb\": \"POST\",\n            \"Path\": \"/api/v1/admin/login\",\n            \"Calls\": [\n                {\n                    \"Id\": 0,\n                    \"CurrentPath\": \"/api/v1/admin/login\",\n                    \"MethodType\": \"POST\",\n                    \"PostForm\": {\n                        \"name\": \"qfeng\"\n                    },\n                    \"RequestHeader\": {\n                        \"Apitoken\": \"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\n                        \"Content-Type\": \" application/x-www-form-urlencoded\\r\"\n                    },\n                    \"CommonRequestHeaders\": null,\n                    \"ResponseHeader\": {\n                        \"Access-Control-Allow-Credentials\": \"true\",\n                        \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n                        \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n                        \"Access-Control-Allow-Origin\": \"*\",\n                        \"Access-Control-Expose-Headers\": \"Content-Length\",\n                        \"Access-Control-Max-Age\": \"86400\",\n                        \"Content-Type\": \"application/json; charset=utf-8\"\n                    },\n                    \"RequestUrlParams\": {},\n                    \"RequestBody\": \"\",\n                    \"ResponseBody\": \"{\\\"sig\\\":\\\"05434ff8db0311e7afde005056a6aba2\\\",\\\"name\\\":\\\"qfeng\\\",\\\"admin\\\":true}\",\n                    \"ResponseCode\": 200\n                },\n                {\n                    \"Id\": 1,\n                    \"CurrentPath\": \"/api/v1/admin/login\",\n                    \"MethodType\": \"POST\",\n                    \"PostForm\": {\n                        \"name\": \"daye\"\n                    },\n                    \"RequestHeader\": {\n                        \"Apitoken\": \"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\n                        \"Content-Type\": \" application/x-www-form-urlencoded\\r\"\n                    },\n                    \"CommonRequestHeaders\": null,\n                    \"ResponseHeader\": {\n                        \"Access-Control-Allow-Credentials\": \"true\",\n                        \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n                        \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n                        \"Access-Control-Allow-Origin\": \"*\",\n                        \"Access-Control-Expose-Headers\": \"Content-Length\",\n                        \"Access-Control-Max-Age\": \"86400\",\n                        \"Content-Type\": \"application/json; charset=utf-8\"\n                    },\n                    \"RequestUrlParams\": {},\n                    \"RequestBody\": \"\",\n                    \"ResponseBody\": \"{\\\"error\\\":\\\"no such user\\\"}\",\n                    \"ResponseCode\": 400\n                },\n                {\n                    \"Id\": 2,\n                    \"CurrentPath\": \"/api/v1/admin/login\",\n                    \"MethodType\": \"POST\",\n                    \"PostForm\": {\n                        \"name\": \"qfeng\"\n                    },\n                    \"RequestHeader\": {\n                        \"Apitoken\": \"{\\\"sig\\\": \\\"05434ff8db0311e7afde005056a6aba2\\\", \\\"name\\\": \\\"qfeng\\\"}\",\n                        \"Content-Type\": \" application/x-www-form-urlencoded\\r\"\n                    },\n                    \"CommonRequestHeaders\": null,\n                    \"ResponseHeader\": {\n                        \"Access-Control-Allow-Credentials\": \"true\",\n                        \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n                        \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n                        \"Access-Control-Allow-Origin\": \"*\",\n                        \"Access-Control-Expose-Headers\": \"Content-Length\",\n                        \"Access-Control-Max-Age\": \"86400\",\n                        \"Content-Type\": \"application/json; charset=utf-8\"\n                    },\n                    \"RequestUrlParams\": {},\n                    \"RequestBody\": \"\",\n                    \"ResponseBody\": \"{\\\"error\\\":\\\"API_USER not admin, no permissions can do this\\\"}\",\n                    \"ResponseCode\": 400\n                }\n            ]\n        },\n        {\n            \"HttpVerb\": \"PUT\",\n            \"Path\": \"/api/v1/admin/change_user_role\",\n            \"Calls\": [\n                {\n                    \"Id\": 3,\n                    \"CurrentPath\": \"/api/v1/admin/change_user_role\",\n                    \"MethodType\": \"PUT\",\n                    \"PostForm\": null,\n                    \"RequestHeader\": {\n                        \"Apitoken\": \"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\n                        \"Content-Type\": \" application/json\\r\"\n                    },\n                    \"CommonRequestHeaders\": null,\n                    \"ResponseHeader\": {\n                        \"Access-Control-Allow-Credentials\": \"true\",\n                        \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n                        \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n                        \"Access-Control-Allow-Origin\": \"*\",\n                        \"Access-Control-Expose-Headers\": \"Content-Length\",\n                        \"Access-Control-Max-Age\": \"86400\",\n                        \"Content-Type\": \"application/json; charset=utf-8\"\n                    },\n                    \"RequestUrlParams\": {},\n                    \"RequestBody\": \"{\\\"admin\\\": \\\"yes\\\", \\\"user_id\\\": 12}\",\n                    \"ResponseBody\": \"{\\\"message\\\":\\\"user role update sccuessful, affect row: 0\\\"}\",\n                    \"ResponseCode\": 200\n                },\n                {\n                    \"Id\": 4,\n                    \"CurrentPath\": \"/api/v1/admin/change_user_role\",\n                    \"MethodType\": \"PUT\",\n                    \"PostForm\": null,\n                    \"RequestHeader\": {\n                        \"Apitoken\": \"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\n                        \"Content-Type\": \" application/json\\r\"\n                    },\n                    \"CommonRequestHeaders\": null,\n                    \"ResponseHeader\": {\n                        \"Access-Control-Allow-Credentials\": \"true\",\n                        \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n                        \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n                        \"Access-Control-Allow-Origin\": \"*\",\n                        \"Access-Control-Expose-Headers\": \"Content-Length\",\n                        \"Access-Control-Max-Age\": \"86400\",\n                        \"Content-Type\": \"application/json; charset=utf-8\"\n                    },\n                    \"RequestUrlParams\": {},\n                    \"RequestBody\": \"{\\\"admin\\\": \\\"no\\\", \\\"user_id\\\": 12}\",\n                    \"ResponseBody\": \"{\\\"message\\\":\\\"user role update sccuessful, affect row: 1\\\"}\",\n                    \"ResponseCode\": 200\n                }\n            ]\n        },\n        {\n            \"HttpVerb\": \"PUT\",\n            \"Path\": \"/api/v1/admin/change_user_passwd\",\n            \"Calls\": [\n                {\n                    \"Id\": 5,\n                    \"CurrentPath\": \"/api/v1/admin/change_user_passwd\",\n                    \"MethodType\": \"PUT\",\n                    \"PostForm\": null,\n                    \"RequestHeader\": {\n                        \"Apitoken\": \"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\n                        \"Content-Type\": \" application/json\\r\"\n                    },\n                    \"CommonRequestHeaders\": null,\n                    \"ResponseHeader\": {\n                        \"Access-Control-Allow-Credentials\": \"true\",\n                        \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n                        \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n                        \"Access-Control-Allow-Origin\": \"*\",\n                        \"Access-Control-Expose-Headers\": \"Content-Length\",\n                        \"Access-Control-Max-Age\": \"86400\",\n                        \"Content-Type\": \"application/json; charset=utf-8\"\n                    },\n                    \"RequestUrlParams\": {},\n                    \"RequestBody\": \"{\\\"password\\\": \\\"lalala\\\", \\\"user_id\\\": 12}\",\n                    \"ResponseBody\": \"{\\\"message\\\":\\\"password updated!\\\"}\",\n                    \"ResponseCode\": 200\n                }\n            ]\n        },\n        {\n            \"HttpVerb\": \"DELETE\",\n            \"Path\": \"/api/v1/admin/delete_user\",\n            \"Calls\": [\n                {\n                    \"Id\": 6,\n                    \"CurrentPath\": \"/api/v1/admin/delete_user\",\n                    \"MethodType\": \"DELETE\",\n                    \"PostForm\": null,\n                    \"RequestHeader\": {\n                        \"Apitoken\": \"{\\\"sig\\\": \\\"25ae3f6cdb1711e79997005056a6aba2\\\", \\\"name\\\": \\\"root\\\"}\",\n                        \"Content-Type\": \" application/json\\r\"\n                    },\n                    \"CommonRequestHeaders\": null,\n                    \"ResponseHeader\": {\n                        \"Access-Control-Allow-Credentials\": \"true\",\n                        \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n                        \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n                        \"Access-Control-Allow-Origin\": \"*\",\n                        \"Access-Control-Expose-Headers\": \"Content-Length\",\n                        \"Access-Control-Max-Age\": \"86400\",\n                        \"Content-Type\": \"application/json; charset=utf-8\"\n                    },\n                    \"RequestUrlParams\": {},\n                    \"RequestBody\": \"{\\\"user_id\\\": 12}\",\n                    \"ResponseBody\": \"{\\\"message\\\":\\\"user 12 has been delete, affect row: 1\\\"}\",\n                    \"ResponseCode\": 200\n                }\n            ]\n        }\n    ]\n}"
  },
  {
    "path": "docs/doc/aggregator.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n    \n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n    \n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n         \n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n        \n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n            \n        \n    </div>\n    \n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n                \n                    <p>Production : <strong>/api/v1</strong></p>\n                \n                    <p>Staging : <strong>/api/v1</strong></p>\n                \n              </div>\n            </div>    \n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n            \n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/aggregator</a></li>\n            \n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/hostgroup/343/aggregator</a></li>\n            \n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/aggregator</a></li>\n            \n                <li role=\"presentation\"><a href=\"#3top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/aggregator/16</a></li>\n            \n                <li role=\"presentation\"><a href=\"#4top\" role=\"tab\" data-toggle=\"tab\">DELETE : /api/v1/aggregator/16</a></li>\n            \n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n        \n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\n</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-0\" class=\"prettyprint\">{&#34;tags&#34;:&#34;&#34;,&#34;step&#34;:60,&#34;numerator&#34;:&#34;$(cpu.idle)&#34;,&#34;metric&#34;:&#34;test.idle&#34;,&#34;hostgroup_id&#34;:343,&#34;endpoint&#34;:&#34;testenp&#34;,&#34;denominator&#34;:&#34;2&#34;}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"hostgroup_id\\\":343,\\\"endpoint\\\":\\\"testenp\\\",\\\"denominator\\\":\\\"2\\\"}\");\n                            document.getElementById('request-body0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">{&#34;id&#34;:16,&#34;grp_id&#34;:343,&#34;numerator&#34;:&#34;$(cpu.idle)&#34;,&#34;denominator&#34;:&#34;2&#34;,&#34;endpoint&#34;:&#34;testenp&#34;,&#34;metric&#34;:&#34;test.idle&#34;,&#34;tags&#34;:&#34;&#34;,&#34;ds_type&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;creator&#34;:&#34;root&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":16,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"}\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">[{&#34;id&#34;:13,&#34;grp_id&#34;:343,&#34;numerator&#34;:&#34;$(cpu.idle)&#34;,&#34;denominator&#34;:&#34;2&#34;,&#34;endpoint&#34;:&#34;testenp&#34;,&#34;metric&#34;:&#34;test.idle&#34;,&#34;tags&#34;:&#34;&#34;,&#34;ds_type&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;creator&#34;:&#34;root&#34;},{&#34;id&#34;:14,&#34;grp_id&#34;:343,&#34;numerator&#34;:&#34;$(cpu.idle)&#34;,&#34;denominator&#34;:&#34;2&#34;,&#34;endpoint&#34;:&#34;testenp&#34;,&#34;metric&#34;:&#34;test.idle&#34;,&#34;tags&#34;:&#34;&#34;,&#34;ds_type&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;creator&#34;:&#34;root&#34;},{&#34;id&#34;:15,&#34;grp_id&#34;:343,&#34;numerator&#34;:&#34;$(cpu.idle)&#34;,&#34;denominator&#34;:&#34;2&#34;,&#34;endpoint&#34;:&#34;testenp&#34;,&#34;metric&#34;:&#34;test.idle&#34;,&#34;tags&#34;:&#34;&#34;,&#34;ds_type&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;creator&#34;:&#34;root&#34;},{&#34;id&#34;:16,&#34;grp_id&#34;:343,&#34;numerator&#34;:&#34;$(cpu.idle)&#34;,&#34;denominator&#34;:&#34;2&#34;,&#34;endpoint&#34;:&#34;testenp&#34;,&#34;metric&#34;:&#34;test.idle&#34;,&#34;tags&#34;:&#34;&#34;,&#34;ds_type&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;creator&#34;:&#34;root&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":13,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"},{\\\"id\\\":14,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"},{\\\"id\\\":15,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"},{\\\"id\\\":16,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"}]\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\n</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-0\" class=\"prettyprint\">{&#34;tags&#34;:&#34;&#34;,&#34;step&#34;:60,&#34;numerator&#34;:&#34;$(cpu.idle)&#34;,&#34;metric&#34;:&#34;test.idle&#34;,&#34;id&#34;:16,&#34;endpoint&#34;:&#34;testenp&#34;,&#34;denominator&#34;:&#34;$#&#34;}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"id\\\":16,\\\"endpoint\\\":\\\"testenp\\\",\\\"denominator\\\":\\\"$#\\\"}\");\n                            document.getElementById('request-body2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">{&#34;id&#34;:16,&#34;grp_id&#34;:343,&#34;numerator&#34;:&#34;$(cpu.idle)&#34;,&#34;denominator&#34;:&#34;$#&#34;,&#34;endpoint&#34;:&#34;testenp&#34;,&#34;metric&#34;:&#34;test.idle&#34;,&#34;tags&#34;:&#34;&#34;,&#34;ds_type&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;creator&#34;:&#34;root&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":16,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"$#\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"}\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"3top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-3-0\">{&#34;id&#34;:16,&#34;grp_id&#34;:343,&#34;numerator&#34;:&#34;$(cpu.idle)&#34;,&#34;denominator&#34;:&#34;$#&#34;,&#34;endpoint&#34;:&#34;testenp&#34;,&#34;metric&#34;:&#34;test.idle&#34;,&#34;tags&#34;:&#34;&#34;,&#34;ds_type&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;creator&#34;:&#34;root&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":16,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"$#\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"}\");\n                            document.getElementById('response-body-3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"4top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-0\">{&#34;message&#34;:&#34;aggregator:16 is deleted&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"aggregator:16 is deleted\\\"}\");\n                            document.getElementById('response-body-4-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>"
  },
  {
    "path": "docs/doc/aggregator.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/aggregator\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/aggregator\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"hostgroup_id\\\":343,\\\"endpoint\\\":\\\"testenp\\\",\\\"denominator\\\":\\\"2\\\"}\",\n          \"ResponseBody\": \"{\\\"id\\\":16,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/hostgroup/343/aggregators\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/hostgroup/343/aggregators\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"hostgroup\\\": \\\"test_group\\\", \\\"aggregators\\\": [{\\\"id\\\":13,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"},{\\\"id\\\":14,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"},{\\\"id\\\":15,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"},{\\\"id\\\":16,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"2\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"}]}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/aggregator\",\n      \"Calls\": [\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/aggregator\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"id\\\":16,\\\"endpoint\\\":\\\"testenp\\\",\\\"denominator\\\":\\\"$#\\\"}\",\n          \"ResponseBody\": \"{\\\"id\\\":16,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"$#\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/aggregator/16\",\n      \"Calls\": [\n        {\n          \"Id\": 3,\n          \"CurrentPath\": \"/api/v1/aggregator/16\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"id\\\":16,\\\"grp_id\\\":343,\\\"numerator\\\":\\\"$(cpu.idle)\\\",\\\"denominator\\\":\\\"$#\\\",\\\"endpoint\\\":\\\"testenp\\\",\\\"metric\\\":\\\"test.idle\\\",\\\"tags\\\":\\\"\\\",\\\"ds_type\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"creator\\\":\\\"root\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"DELETE\",\n      \"Path\": \"/api/v1/aggregator/16\",\n      \"Calls\": [\n        {\n          \"Id\": 4,\n          \"CurrentPath\": \"/api/v1/aggregator/16\",\n          \"MethodType\": \"DELETE\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"aggregator:16 is deleted\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/alarm.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n    \n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n    \n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n         \n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n        \n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n            \n        \n    </div>\n    \n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n                \n                    <p>Production : <strong>/api/v1</strong></p>\n                \n                    <p>Staging : <strong>/api/v1</strong></p>\n                \n              </div>\n            </div>    \n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n            \n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/alarm/eventcases</a></li>\n            \n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/alarm/event_note</a></li>\n            \n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/alarm/event_note</a></li>\n            \n                <li role=\"presentation\"><a href=\"#3top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/alarm/eventcases</a></li>\n            \n                <li role=\"presentation\"><a href=\"#4top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/alarm/events</a></li>\n            \n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n        \n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-0\" class=\"prettyprint\">\n\t\t\t{\n\t      &#34;startTime&#34;: 1466956800,\n\t    \t&#34;endTime&#34;: 1480521600,\n\t    \t&#34;status&#34;: &#34;PROBLEM&#34;,\n\t    \t&#34;process_status&#34;: &#34;ignored,unresolved&#34;,\n\t    \t&#34;limit&#34;: 10\n\t    }</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t    \\t\\\"endTime\\\": 1480521600,\\n\\t    \\t\\\"status\\\": \\\"PROBLEM\\\",\\n\\t    \\t\\\"process_status\\\": \\\"ignored,unresolved\\\",\\n\\t    \\t\\\"limit\\\": 10\\n\\t    }\");\n                            document.getElementById('request-body0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">[{&#34;id&#34;:&#34;s_46_1ac45122afb893adc02fbd30154ac303&#34;,&#34;endpoint&#34;:&#34;agent4&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;all(#3)&#34;,&#34;cond&#34;:&#34;48.33759590792839 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;PROBLEM&#34;,&#34;timestamp&#34;:&#34;2016-08-01T06:25:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-08-01T06:25:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:46,&#34;template_id&#34;:126,&#34;process_note&#34;:16907,&#34;process_status&#34;:&#34;ignored&#34;},{&#34;id&#34;:&#34;s_50_6438ac68b30e2712fb8f00d894c46e21&#34;,&#34;endpoint&#34;:&#34;agent5&#34;,&#34;metric&#34;:&#34;cpu.idle&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;95.16331658291456 \\u003c= 98&#34;,&#34;note&#34;:&#34;cpu空闲值报警&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:3,&#34;status&#34;:&#34;PROBLEM&#34;,&#34;timestamp&#34;:&#34;2016-07-03T16:13:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-07-03T16:13:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:50,&#34;template_id&#34;:53,&#34;process_note&#34;:1181,&#34;process_status&#34;:&#34;ignored&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":\\\"s_46_1ac45122afb893adc02fbd30154ac303\\\",\\\"endpoint\\\":\\\"agent4\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"cond\\\":\\\"48.33759590792839 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2016-08-01T06:25:00+08:00\\\",\\\"update_at\\\":\\\"2016-08-01T06:25:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":46,\\\"template_id\\\":126,\\\"process_note\\\":16907,\\\"process_status\\\":\\\"ignored\\\"},{\\\"id\\\":\\\"s_50_6438ac68b30e2712fb8f00d894c46e21\\\",\\\"endpoint\\\":\\\"agent5\\\",\\\"metric\\\":\\\"cpu.idle\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"95.16331658291456 \\\\u003c= 98\\\",\\\"note\\\":\\\"cpu空闲值报警\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":3,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2016-07-03T16:13:00+08:00\\\",\\\"update_at\\\":\\\"2016-07-03T16:13:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":50,\\\"template_id\\\":53,\\\"process_note\\\":1181,\\\"process_status\\\":\\\"ignored\\\"}]\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-1\" class=\"prettyprint\">\n\t\t\t{\n\t      &#34;startTime&#34;: 1466956800,\n\t    \t&#34;endTime&#34;: 1480521600,\n\t    \t&#34;status&#34;: &#34;PROBLEM,OK&#34;,\n\t    \t&#34;process_status&#34;: &#34;ignored,unresolved&#34;,\n\t    \t&#34;limit&#34;: 10\n\t    }</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t    \\t\\\"endTime\\\": 1480521600,\\n\\t    \\t\\\"status\\\": \\\"PROBLEM,OK\\\",\\n\\t    \\t\\\"process_status\\\": \\\"ignored,unresolved\\\",\\n\\t    \\t\\\"limit\\\": 10\\n\\t    }\");\n                            document.getElementById('request-body0-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-1\">[{&#34;id&#34;:&#34;s_322_00c5f5c87a71bd4c686c0a4a0544b719&#34;,&#34;endpoint&#34;:&#34;agent8&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;0 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-11-30T20:10:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-11-30T20:10:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:125,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;},{&#34;id&#34;:&#34;s_322_00a9b9f9f859d8436f9b643ea5a1fb5e&#34;,&#34;endpoint&#34;:&#34;agent6&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;0 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-11-14T22:16:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-11-14T22:16:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:140,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;},{&#34;id&#34;:&#34;s_322_00ba3072006a8ba863108d4b3f9c1c51&#34;,&#34;endpoint&#34;:&#34;agent7&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;0.0695615485072203 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-11-14T20:43:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-11-14T20:43:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:125,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;},{&#34;id&#34;:&#34;s_322_002e499f3b56420fdea506c887e51799&#34;,&#34;endpoint&#34;:&#34;agent3&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;30.76679150609009 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-11-07T04:28:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-11-07T04:28:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:125,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;},{&#34;id&#34;:&#34;s_322_00cc81434a0e277b57254a89a839a47b&#34;,&#34;endpoint&#34;:&#34;agent9&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;0.041876046901172526 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-10-28T10:37:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-10-28T10:37:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:125,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;},{&#34;id&#34;:&#34;s_322_001da6a5f95d83387cdfecc37ac70c24&#34;,&#34;endpoint&#34;:&#34;agent2&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;34.40479690409319 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-10-27T15:37:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-10-27T15:37:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:125,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;},{&#34;id&#34;:&#34;s_46_1ac45122afb893adc02fbd30154ac303&#34;,&#34;endpoint&#34;:&#34;agent4&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;all(#3)&#34;,&#34;cond&#34;:&#34;48.33759590792839 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;PROBLEM&#34;,&#34;timestamp&#34;:&#34;2016-08-01T06:25:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-08-01T06:25:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:46,&#34;template_id&#34;:126,&#34;process_note&#34;:16907,&#34;process_status&#34;:&#34;ignored&#34;},{&#34;id&#34;:&#34;s_191_ddd09333257b2e92e1941860ee86ab15&#34;,&#34;endpoint&#34;:&#34;agent1&#34;,&#34;metric&#34;:&#34;cpu.idle&#34;,&#34;func&#34;:&#34;all(#3)&#34;,&#34;cond&#34;:&#34;11.813186813186814 \\u003c 10&#34;,&#34;note&#34;:&#34;cpu.idle小于10%&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:3,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-07-06T09:13:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-07-06T09:13:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:191,&#34;template_id&#34;:42,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;},{&#34;id&#34;:&#34;s_50_6438ac68b30e2712fb8f00d894c46e21&#34;,&#34;endpoint&#34;:&#34;agent5&#34;,&#34;metric&#34;:&#34;cpu.idle&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;95.16331658291456 \\u003c= 98&#34;,&#34;note&#34;:&#34;cpu空闲值报警&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:3,&#34;status&#34;:&#34;PROBLEM&#34;,&#34;timestamp&#34;:&#34;2016-07-03T16:13:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-07-03T16:13:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:50,&#34;template_id&#34;:53,&#34;process_note&#34;:1181,&#34;process_status&#34;:&#34;ignored&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":\\\"s_322_00c5f5c87a71bd4c686c0a4a0544b719\\\",\\\"endpoint\\\":\\\"agent8\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_00a9b9f9f859d8436f9b643ea5a1fb5e\\\",\\\"endpoint\\\":\\\"agent6\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-14T22:16:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-14T22:16:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":140,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_00ba3072006a8ba863108d4b3f9c1c51\\\",\\\"endpoint\\\":\\\"agent7\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0.0695615485072203 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-14T20:43:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-14T20:43:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_002e499f3b56420fdea506c887e51799\\\",\\\"endpoint\\\":\\\"agent3\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"30.76679150609009 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-07T04:28:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-07T04:28:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_00cc81434a0e277b57254a89a839a47b\\\",\\\"endpoint\\\":\\\"agent9\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0.041876046901172526 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-10-28T10:37:00+08:00\\\",\\\"update_at\\\":\\\"2016-10-28T10:37:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_001da6a5f95d83387cdfecc37ac70c24\\\",\\\"endpoint\\\":\\\"agent2\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"34.40479690409319 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-10-27T15:37:00+08:00\\\",\\\"update_at\\\":\\\"2016-10-27T15:37:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_46_1ac45122afb893adc02fbd30154ac303\\\",\\\"endpoint\\\":\\\"agent4\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"cond\\\":\\\"48.33759590792839 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2016-08-01T06:25:00+08:00\\\",\\\"update_at\\\":\\\"2016-08-01T06:25:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":46,\\\"template_id\\\":126,\\\"process_note\\\":16907,\\\"process_status\\\":\\\"ignored\\\"},{\\\"id\\\":\\\"s_191_ddd09333257b2e92e1941860ee86ab15\\\",\\\"endpoint\\\":\\\"agent1\\\",\\\"metric\\\":\\\"cpu.idle\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"cond\\\":\\\"11.813186813186814 \\\\u003c 10\\\",\\\"note\\\":\\\"cpu.idle小于10%\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":3,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-07-06T09:13:00+08:00\\\",\\\"update_at\\\":\\\"2016-07-06T09:13:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":191,\\\"template_id\\\":42,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_50_6438ac68b30e2712fb8f00d894c46e21\\\",\\\"endpoint\\\":\\\"agent5\\\",\\\"metric\\\":\\\"cpu.idle\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"95.16331658291456 \\\\u003c= 98\\\",\\\"note\\\":\\\"cpu空闲值报警\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":3,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2016-07-03T16:13:00+08:00\\\",\\\"update_at\\\":\\\"2016-07-03T16:13:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":50,\\\"template_id\\\":53,\\\"process_note\\\":1181,\\\"process_status\\\":\\\"ignored\\\"}]\");\n                            document.getElementById('response-body-0-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-2\" class=\"prettyprint\">\n\t\t\t{\n\t      &#34;startTime&#34;: 1466956800,\n\t      &#34;endTime&#34;: 1480521600,\n\t      &#34;status&#34;: &#34;PROBLEM&#34;,\n\t      &#34;process_status&#34;: &#34;unresolved&#34;,\n\t      &#34;limit&#34;: 10\n\t    }</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t      \\\"endTime\\\": 1480521600,\\n\\t      \\\"status\\\": \\\"PROBLEM\\\",\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t      \\\"limit\\\": 10\\n\\t    }\");\n                            document.getElementById('request-body0-2').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-2\">[]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[]\");\n                            document.getElementById('response-body-0-2').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-3\" class=\"prettyprint\">\n\t\t\t{\n\t      &#34;startTime&#34;: 1466956800,\n\t      &#34;endTime&#34;: 1480521600,\n\t      &#34;process_status&#34;: &#34;unresolved&#34;,\n\t      &#34;limit&#34;: 1\n\t    }</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t      \\\"endTime\\\": 1480521600,\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t      \\\"limit\\\": 1\\n\\t    }\");\n                            document.getElementById('request-body0-3').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-3\">[{&#34;id&#34;:&#34;s_322_00c5f5c87a71bd4c686c0a4a0544b719&#34;,&#34;endpoint&#34;:&#34;agent8&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;0 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-11-30T20:10:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-11-30T20:10:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:125,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":\\\"s_322_00c5f5c87a71bd4c686c0a4a0544b719\\\",\\\"endpoint\\\":\\\"agent8\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"}]\");\n                            document.getElementById('response-body-0-3').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-4\" class=\"prettyprint\">\n\t\t\t{\n\t      &#34;startTime&#34;: 1477584000,\n\t      &#34;endTime&#34;: 1477670400,\n\t      &#34;process_status&#34;: &#34;unresolved&#34;,\n\t      &#34;limit&#34;: 10\n\t    }</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1477584000,\\n\\t      \\\"endTime\\\": 1477670400,\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t      \\\"limit\\\": 10\\n\\t    }\");\n                            document.getElementById('request-body0-4').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-4\">[{&#34;id&#34;:&#34;s_322_00cc81434a0e277b57254a89a839a47b&#34;,&#34;endpoint&#34;:&#34;agent9&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;0.041876046901172526 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-10-28T10:37:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-10-28T10:37:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:125,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":\\\"s_322_00cc81434a0e277b57254a89a839a47b\\\",\\\"endpoint\\\":\\\"agent9\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0.041876046901172526 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-10-28T10:37:00+08:00\\\",\\\"update_at\\\":\\\"2016-10-28T10:37:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"}]\");\n                            document.getElementById('response-body-0-4').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-5\" class=\"prettyprint\">\n\t\t\t{\n\t      &#34;startTime&#34;: 1466956800,\n\t      &#34;endTime&#34;: 1480521600,\n\t      &#34;process_status&#34;: &#34;unresolved&#34;,\n\t\t\t\t&#34;page&#34;: 0,\n\t      &#34;limit&#34;: 1\n\t    }</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t      \\\"endTime\\\": 1480521600,\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t\\t\\t\\t\\\"page\\\": 0,\\n\\t      \\\"limit\\\": 1\\n\\t    }\");\n                            document.getElementById('request-body0-5').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-5\">[{&#34;id&#34;:&#34;s_322_00c5f5c87a71bd4c686c0a4a0544b719&#34;,&#34;endpoint&#34;:&#34;agent8&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;0 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-11-30T20:10:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-11-30T20:10:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:125,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":\\\"s_322_00c5f5c87a71bd4c686c0a4a0544b719\\\",\\\"endpoint\\\":\\\"agent8\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"}]\");\n                            document.getElementById('response-body-0-5').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-6\" class=\"prettyprint\">\n\t\t\t{\n\t      &#34;startTime&#34;: 1466956800,\n\t      &#34;endTime&#34;: 1480521600,\n\t      &#34;process_status&#34;: &#34;unresolved&#34;,\n\t\t\t\t&#34;page&#34;: 1,\n\t      &#34;limit&#34;: 1\n\t    }</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t      \\\"endTime\\\": 1480521600,\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t\\t\\t\\t\\\"page\\\": 1,\\n\\t      \\\"limit\\\": 1\\n\\t    }\");\n                            document.getElementById('request-body0-6').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-6\">[{&#34;id&#34;:&#34;s_322_00a9b9f9f859d8436f9b643ea5a1fb5e&#34;,&#34;endpoint&#34;:&#34;agent6&#34;,&#34;metric&#34;:&#34;cpu.iowait&#34;,&#34;func&#34;:&#34;avg(#3)&#34;,&#34;cond&#34;:&#34;0 \\u003e 40&#34;,&#34;note&#34;:&#34;CPU I/O wait超过40&#34;,&#34;step&#34;:1,&#34;current_step&#34;:1,&#34;priority&#34;:1,&#34;status&#34;:&#34;OK&#34;,&#34;timestamp&#34;:&#34;2016-11-14T22:16:00&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-11-14T22:16:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:322,&#34;template_id&#34;:140,&#34;process_note&#34;:0,&#34;process_status&#34;:&#34;unresolved&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":\\\"s_322_00a9b9f9f859d8436f9b643ea5a1fb5e\\\",\\\"endpoint\\\":\\\"agent6\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-14T22:16:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-14T22:16:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":140,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"}]\");\n                            document.getElementById('response-body-0-6').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>endTime</td>\n                        <td> 1466697600</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>startTime</td>\n                        <td> 1466611200</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">[{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2016-06-23T05:39:09&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_9d223f126e7ecb3477cd6806f1ee9656&#34;,&#34;note&#34;:&#34;Ignored by user&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2016-06-23T05:38:56&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2016-06-23T05:39:09+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_9d223f126e7ecb3477cd6806f1ee9656\\\",\\\"note\\\":\\\"Ignored by user\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2016-06-23T05:38:56+08:00\\\",\\\"user\\\":\\\"root\\\"}]\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>event_id</td>\n                        <td> s_165_cef145900bf4e2a4a0db8b85762b9cdb</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-1\">[{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:50:29&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:50:29&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:50:06&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:50:06&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:48:07&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:48:07&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:47:24&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:47:24&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:45:04&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:45:04&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:43:26&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:43:26&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:42:02&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:42:02&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:41:14&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:41:14&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:41:02&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:41:01&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:39:49&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:39:49&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:37:50&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:37:50&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:36:34&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:36:34&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:33:50&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:33:50&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:32:52&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:32:52&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:18:12&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;a000001&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:18:12&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:34:15&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:34:15&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:30:51&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:30:51&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:30:03&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:30:03&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:30:03&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:30:03&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:29:44&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:29:44&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:20:42&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T20:20:42&#43;08:00&#34;,&#34;user&#34;:&#34;root&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T18:58:41&#43;08:00&#34;,&#34;user&#34;:&#34;owl&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T18:58:41&#43;08:00&#34;,&#34;user&#34;:&#34;owl&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T18:58:04&#43;08:00&#34;,&#34;user&#34;:&#34;owl&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T18:58:04&#43;08:00&#34;,&#34;user&#34;:&#34;owl&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T18:56:35&#43;08:00&#34;,&#34;user&#34;:&#34;owl&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T18:56:35&#43;08:00&#34;,&#34;user&#34;:&#34;owl&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;comment&#34;,&#34;timestamp&#34;:&#34;2017-03-22T18:56:25&#43;08:00&#34;,&#34;user&#34;:&#34;owl&#34;},{&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;note&#34;:&#34;test note&#34;,&#34;case_id&#34;:&#34;&#34;,&#34;status&#34;:&#34;ignored&#34;,&#34;timestamp&#34;:&#34;2017-03-22T18:56:25&#43;08:00&#34;,&#34;user&#34;:&#34;owl&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:50:29+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:50:29+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:50:06+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:50:06+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:48:07+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:48:07+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:47:24+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:47:24+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:45:04+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:45:04+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:43:26+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:43:26+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:42:02+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:42:02+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:41:14+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:41:14+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:41:02+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:41:01+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:39:49+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:39:49+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:37:50+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:37:50+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:36:34+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:36:34+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:33:50+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:33:50+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:32:52+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:32:52+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:18:12+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:18:12+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:34:15+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:34:15+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:51+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:51+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:03+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:03+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:03+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:03+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:29:44+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:29:44+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:20:42+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:20:42+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T18:58:41+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T18:58:41+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T18:58:04+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T18:58:04+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T18:56:35+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T18:56:35+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T18:56:25+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T18:56:25+08:00\\\",\\\"user\\\":\\\"owl\\\"}]\");\n                            document.getElementById('response-body-1-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-0\" class=\"prettyprint\">\n\t\t\t{\n\t\t\t\t&#34;event_id&#34;: &#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,\n\t\t\t\t&#34;note&#34;: &#34;test note&#34;,\n\t\t\t\t&#34;status&#34;: &#34;comment&#34;\n\t\t\t}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"\\n\\t\\t\\t{\\n\\t\\t\\t\\t\\\"event_id\\\": \\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\n\\t\\t\\t\\t\\\"note\\\": \\\"test note\\\",\\n\\t\\t\\t\\t\\\"status\\\": \\\"comment\\\"\\n\\t\\t\\t}\");\n                            document.getElementById('request-body2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">{&#34;id&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;message&#34;:&#34;add note to s_165_cef145900bf4e2a4a0db8b85762b9cdb successfuled&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"message\\\":\\\"add note to s_165_cef145900bf4e2a4a0db8b85762b9cdb successfuled\\\"}\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-1\" class=\"prettyprint\">\n\t\t\t{\n\t\t\t\t&#34;event_id&#34;: &#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,\n\t\t\t\t&#34;note&#34;: &#34;test note&#34;,\n\t\t\t\t&#34;status&#34;: &#34;ignored&#34;,\n\t\t\t\t&#34;case_id&#34;: &#34;a000001&#34;\n\t\t\t}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\"Content-Type\":\" application/json\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"\\n\\t\\t\\t{\\n\\t\\t\\t\\t\\\"event_id\\\": \\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\n\\t\\t\\t\\t\\\"note\\\": \\\"test note\\\",\\n\\t\\t\\t\\t\\\"status\\\": \\\"ignored\\\",\\n\\t\\t\\t\\t\\\"case_id\\\": \\\"a000001\\\"\\n\\t\\t\\t}\");\n                            document.getElementById('request-body2-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-1\">{&#34;id&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;message&#34;:&#34;add note to s_165_cef145900bf4e2a4a0db8b85762b9cdb successfuled&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"message\\\":\\\"add note to s_165_cef145900bf4e2a4a0db8b85762b9cdb successfuled\\\"}\");\n                            document.getElementById('response-body-2-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"3top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>event_id</td>\n                        <td> s_165_cef145900bf4e2a4a0db8b85762b9cdb</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-3-0\">[{&#34;id&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;endpoint&#34;:&#34;agent2&#34;,&#34;metric&#34;:&#34;cpu.idle&#34;,&#34;func&#34;:&#34;all(#1)&#34;,&#34;cond&#34;:&#34;0 != 66&#34;,&#34;note&#34;:&#34;測試告警自動更新&#34;,&#34;step&#34;:300,&#34;current_step&#34;:3,&#34;priority&#34;:0,&#34;status&#34;:&#34;PROBLEM&#34;,&#34;timestamp&#34;:&#34;2017-03-23T15:51:11&#43;08:00&#34;,&#34;update_at&#34;:&#34;2016-06-23T05:00:00&#43;08:00&#34;,&#34;closed_at&#34;:null,&#34;closed_note&#34;:&#34;&#34;,&#34;user_modified&#34;:0,&#34;tpl_creator&#34;:&#34;root&#34;,&#34;expression_id&#34;:0,&#34;strategy_id&#34;:165,&#34;template_id&#34;:45,&#34;process_note&#34;:56603,&#34;process_status&#34;:&#34;ignored&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"endpoint\\\":\\\"agent2\\\",\\\"metric\\\":\\\"cpu.idle\\\",\\\"func\\\":\\\"all(#1)\\\",\\\"cond\\\":\\\"0 != 66\\\",\\\"note\\\":\\\"測試告警自動更新\\\",\\\"step\\\":300,\\\"current_step\\\":3,\\\"priority\\\":0,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2017-03-23T15:51:11+08:00\\\",\\\"update_at\\\":\\\"2016-06-23T05:00:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":165,\\\"template_id\\\":45,\\\"process_note\\\":56603,\\\"process_status\\\":\\\"ignored\\\"}]\");\n                            document.getElementById('response-body-3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"4top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/x-www-form-urlencoded\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Post Form </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>endTime</td>\n                        <td> 1466628960</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>event_id</td>\n                        <td> s_165_cef145900bf4e2a4a0db8b85762b9cdb</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>startTime</td>\n                        <td> 1466611200</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-0\">[{&#34;id&#34;:635166,&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;step&#34;:0,&#34;cond&#34;:&#34;10.649350649350648 != 66&#34;,&#34;status&#34;:0,&#34;timestamp&#34;:&#34;2016-06-23T04:55:00&#43;08:00&#34;},{&#34;id&#34;:635149,&#34;event_caseId&#34;:&#34;s_165_cef145900bf4e2a4a0db8b85762b9cdb&#34;,&#34;step&#34;:0,&#34;cond&#34;:&#34;13.486005089058525 != 66&#34;,&#34;status&#34;:0,&#34;timestamp&#34;:&#34;2016-06-23T04:50:00&#43;08:00&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":635166,\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"step\\\":0,\\\"cond\\\":\\\"10.649350649350648 != 66\\\",\\\"status\\\":0,\\\"timestamp\\\":\\\"2016-06-23T04:55:00+08:00\\\"},{\\\"id\\\":635149,\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"step\\\":0,\\\"cond\\\":\\\"13.486005089058525 != 66\\\",\\\"status\\\":0,\\\"timestamp\\\":\\\"2016-06-23T04:50:00+08:00\\\"}]\");\n                            document.getElementById('response-body-4-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/x-www-form-urlencoded\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Post Form </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>event_id</td>\n                        <td> s_322_00f5a68989281d30fbbb647194a09230</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>limit</td>\n                        <td> 2</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>status</td>\n                        <td> 1</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-1\">[{&#34;id&#34;:2283581,&#34;event_caseId&#34;:&#34;s_322_00f5a68989281d30fbbb647194a09230&#34;,&#34;step&#34;:0,&#34;cond&#34;:&#34;0 \\u003e 40&#34;,&#34;status&#34;:1,&#34;timestamp&#34;:&#34;2016-12-08T02:10:00&#43;08:00&#34;},{&#34;id&#34;:2229288,&#34;event_caseId&#34;:&#34;s_322_00f5a68989281d30fbbb647194a09230&#34;,&#34;step&#34;:0,&#34;cond&#34;:&#34;0.8756834205893638 \\u003e 40&#34;,&#34;status&#34;:1,&#34;timestamp&#34;:&#34;2016-12-02T15:43:00&#43;08:00&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":2283581,\\\"event_caseId\\\":\\\"s_322_00f5a68989281d30fbbb647194a09230\\\",\\\"step\\\":0,\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"status\\\":1,\\\"timestamp\\\":\\\"2016-12-08T02:10:00+08:00\\\"},{\\\"id\\\":2229288,\\\"event_caseId\\\":\\\"s_322_00f5a68989281d30fbbb647194a09230\\\",\\\"step\\\":0,\\\"cond\\\":\\\"0.8756834205893638 \\\\u003e 40\\\",\\\"status\\\":1,\\\"timestamp\\\":\\\"2016-12-02T15:43:00+08:00\\\"}]\");\n                            document.getElementById('response-body-4-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/x-www-form-urlencoded\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Post Form </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>event_id</td>\n                        <td> s_322_00f5a68989281d30fbbb647194a09230</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>limit</td>\n                        <td> 1</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>page</td>\n                        <td> 0</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-2\">[{&#34;id&#34;:2283581,&#34;event_caseId&#34;:&#34;s_322_00f5a68989281d30fbbb647194a09230&#34;,&#34;step&#34;:0,&#34;cond&#34;:&#34;0 \\u003e 40&#34;,&#34;status&#34;:1,&#34;timestamp&#34;:&#34;2016-12-08T02:10:00&#43;08:00&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":2283581,\\\"event_caseId\\\":\\\"s_322_00f5a68989281d30fbbb647194a09230\\\",\\\"step\\\":0,\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"status\\\":1,\\\"timestamp\\\":\\\"2016-12-08T02:10:00+08:00\\\"}]\");\n                            document.getElementById('response-body-4-2').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;233fdb00f99811e68a5c001500c6ca5a&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/x-www-form-urlencoded\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Post Form </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>event_id</td>\n                        <td> s_322_00f5a68989281d30fbbb647194a09230</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>limit</td>\n                        <td> 1</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>page</td>\n                        <td> 1</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-3\">[{&#34;id&#34;:2283566,&#34;event_caseId&#34;:&#34;s_322_00f5a68989281d30fbbb647194a09230&#34;,&#34;step&#34;:0,&#34;cond&#34;:&#34;2.5609807127182493e&#43;17 \\u003e 40&#34;,&#34;status&#34;:0,&#34;timestamp&#34;:&#34;2016-12-08T02:07:00&#43;08:00&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":2283566,\\\"event_caseId\\\":\\\"s_322_00f5a68989281d30fbbb647194a09230\\\",\\\"step\\\":0,\\\"cond\\\":\\\"2.5609807127182493e+17 \\\\u003e 40\\\",\\\"status\\\":0,\\\"timestamp\\\":\\\"2016-12-08T02:07:00+08:00\\\"}]\");\n                            document.getElementById('response-body-4-3').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>"
  },
  {
    "path": "docs/doc/alarm.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/alarm/eventcases\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/alarm/eventcases\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/json\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t    \\t\\\"endTime\\\": 1480521600,\\n\\t    \\t\\\"status\\\": \\\"PROBLEM\\\",\\n\\t    \\t\\\"process_status\\\": \\\"ignored,unresolved\\\",\\n\\t    \\t\\\"limit\\\": 10\\n\\t    }\",\n          \"ResponseBody\": \"[{\\\"id\\\":\\\"s_46_1ac45122afb893adc02fbd30154ac303\\\",\\\"endpoint\\\":\\\"agent4\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"cond\\\":\\\"48.33759590792839 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2016-08-01T06:25:00+08:00\\\",\\\"update_at\\\":\\\"2016-08-01T06:25:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":46,\\\"template_id\\\":126,\\\"process_note\\\":16907,\\\"process_status\\\":\\\"ignored\\\"},{\\\"id\\\":\\\"s_50_6438ac68b30e2712fb8f00d894c46e21\\\",\\\"endpoint\\\":\\\"agent5\\\",\\\"metric\\\":\\\"cpu.idle\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"95.16331658291456 \\\\u003c= 98\\\",\\\"note\\\":\\\"cpu空闲值报警\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":3,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2016-07-03T16:13:00+08:00\\\",\\\"update_at\\\":\\\"2016-07-03T16:13:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":50,\\\"template_id\\\":53,\\\"process_note\\\":1181,\\\"process_status\\\":\\\"ignored\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/alarm/eventcases\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/json\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t    \\t\\\"endTime\\\": 1480521600,\\n\\t    \\t\\\"status\\\": \\\"PROBLEM,OK\\\",\\n\\t    \\t\\\"process_status\\\": \\\"ignored,unresolved\\\",\\n\\t    \\t\\\"limit\\\": 10\\n\\t    }\",\n          \"ResponseBody\": \"[{\\\"id\\\":\\\"s_322_00c5f5c87a71bd4c686c0a4a0544b719\\\",\\\"endpoint\\\":\\\"agent8\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_00a9b9f9f859d8436f9b643ea5a1fb5e\\\",\\\"endpoint\\\":\\\"agent6\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-14T22:16:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-14T22:16:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":140,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_00ba3072006a8ba863108d4b3f9c1c51\\\",\\\"endpoint\\\":\\\"agent7\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0.0695615485072203 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-14T20:43:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-14T20:43:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_002e499f3b56420fdea506c887e51799\\\",\\\"endpoint\\\":\\\"agent3\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"30.76679150609009 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-07T04:28:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-07T04:28:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_00cc81434a0e277b57254a89a839a47b\\\",\\\"endpoint\\\":\\\"agent9\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0.041876046901172526 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-10-28T10:37:00+08:00\\\",\\\"update_at\\\":\\\"2016-10-28T10:37:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_322_001da6a5f95d83387cdfecc37ac70c24\\\",\\\"endpoint\\\":\\\"agent2\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"34.40479690409319 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-10-27T15:37:00+08:00\\\",\\\"update_at\\\":\\\"2016-10-27T15:37:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_46_1ac45122afb893adc02fbd30154ac303\\\",\\\"endpoint\\\":\\\"agent4\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"cond\\\":\\\"48.33759590792839 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2016-08-01T06:25:00+08:00\\\",\\\"update_at\\\":\\\"2016-08-01T06:25:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":46,\\\"template_id\\\":126,\\\"process_note\\\":16907,\\\"process_status\\\":\\\"ignored\\\"},{\\\"id\\\":\\\"s_191_ddd09333257b2e92e1941860ee86ab15\\\",\\\"endpoint\\\":\\\"agent1\\\",\\\"metric\\\":\\\"cpu.idle\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"cond\\\":\\\"11.813186813186814 \\\\u003c 10\\\",\\\"note\\\":\\\"cpu.idle小于10%\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":3,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-07-06T09:13:00+08:00\\\",\\\"update_at\\\":\\\"2016-07-06T09:13:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":191,\\\"template_id\\\":42,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"},{\\\"id\\\":\\\"s_50_6438ac68b30e2712fb8f00d894c46e21\\\",\\\"endpoint\\\":\\\"agent5\\\",\\\"metric\\\":\\\"cpu.idle\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"95.16331658291456 \\\\u003c= 98\\\",\\\"note\\\":\\\"cpu空闲值报警\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":3,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2016-07-03T16:13:00+08:00\\\",\\\"update_at\\\":\\\"2016-07-03T16:13:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":50,\\\"template_id\\\":53,\\\"process_note\\\":1181,\\\"process_status\\\":\\\"ignored\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/alarm/eventcases\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/json\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t      \\\"endTime\\\": 1480521600,\\n\\t      \\\"status\\\": \\\"PROBLEM\\\",\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t      \\\"limit\\\": 10\\n\\t    }\",\n          \"ResponseBody\": \"[]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 3,\n          \"CurrentPath\": \"/api/v1/alarm/eventcases\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/json\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t      \\\"endTime\\\": 1480521600,\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t      \\\"limit\\\": 1\\n\\t    }\",\n          \"ResponseBody\": \"[{\\\"id\\\":\\\"s_322_00c5f5c87a71bd4c686c0a4a0544b719\\\",\\\"endpoint\\\":\\\"agent8\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 4,\n          \"CurrentPath\": \"/api/v1/alarm/eventcases\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/json\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1477584000,\\n\\t      \\\"endTime\\\": 1477670400,\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t      \\\"limit\\\": 10\\n\\t    }\",\n          \"ResponseBody\": \"[{\\\"id\\\":\\\"s_322_00cc81434a0e277b57254a89a839a47b\\\",\\\"endpoint\\\":\\\"agent9\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0.041876046901172526 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-10-28T10:37:00+08:00\\\",\\\"update_at\\\":\\\"2016-10-28T10:37:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 5,\n          \"CurrentPath\": \"/api/v1/alarm/eventcases\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/json\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t      \\\"endTime\\\": 1480521600,\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t\\t\\t\\t\\\"page\\\": 0,\\n\\t      \\\"limit\\\": 1\\n\\t    }\",\n          \"ResponseBody\": \"[{\\\"id\\\":\\\"s_322_00c5f5c87a71bd4c686c0a4a0544b719\\\",\\\"endpoint\\\":\\\"agent8\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-30T20:10:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":125,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 6,\n          \"CurrentPath\": \"/api/v1/alarm/eventcases\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/json\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\\n\\t\\t\\t{\\n\\t      \\\"startTime\\\": 1466956800,\\n\\t      \\\"endTime\\\": 1480521600,\\n\\t      \\\"process_status\\\": \\\"unresolved\\\",\\n\\t\\t\\t\\t\\\"page\\\": 1,\\n\\t      \\\"limit\\\": 1\\n\\t    }\",\n          \"ResponseBody\": \"[{\\\"id\\\":\\\"s_322_00a9b9f9f859d8436f9b643ea5a1fb5e\\\",\\\"endpoint\\\":\\\"agent6\\\",\\\"metric\\\":\\\"cpu.iowait\\\",\\\"func\\\":\\\"avg(#3)\\\",\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"note\\\":\\\"CPU I/O wait超过40\\\",\\\"step\\\":1,\\\"current_step\\\":1,\\\"priority\\\":1,\\\"status\\\":\\\"OK\\\",\\\"timestamp\\\":\\\"2016-11-14T22:16:00+08:00\\\",\\\"update_at\\\":\\\"2016-11-14T22:16:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":322,\\\"template_id\\\":140,\\\"process_note\\\":0,\\\"process_status\\\":\\\"unresolved\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/alarm/event_note\",\n      \"Calls\": [\n        {\n          \"Id\": 7,\n          \"CurrentPath\": \"/api/v1/alarm/event_note\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"endTime\": \"1466697600\",\n            \"startTime\": \"1466611200\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2016-06-23T05:39:09+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_9d223f126e7ecb3477cd6806f1ee9656\\\",\\\"note\\\":\\\"Ignored by user\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2016-06-23T05:38:56+08:00\\\",\\\"user\\\":\\\"root\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 8,\n          \"CurrentPath\": \"/api/v1/alarm/event_note\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"event_id\": \"s_165_cef145900bf4e2a4a0db8b85762b9cdb\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:50:29+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:50:29+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:50:06+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:50:06+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:48:07+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:48:07+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:47:24+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:47:24+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:45:04+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:45:04+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:43:26+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:43:26+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:42:02+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:42:02+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:41:14+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:41:14+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:41:02+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:41:01+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:39:49+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:39:49+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:37:50+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:37:50+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:36:34+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:36:34+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:33:50+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:33:50+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:32:52+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:32:52+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-23T15:18:12+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"a000001\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-23T15:18:12+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:34:15+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:34:15+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:51+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:51+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:03+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:03+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:03+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:30:03+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:29:44+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:29:44+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T20:20:42+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T20:20:42+08:00\\\",\\\"user\\\":\\\"root\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T18:58:41+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T18:58:41+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T18:58:04+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T18:58:04+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T18:56:35+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T18:56:35+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"comment\\\",\\\"timestamp\\\":\\\"2017-03-22T18:56:25+08:00\\\",\\\"user\\\":\\\"owl\\\"},{\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"note\\\":\\\"test note\\\",\\\"case_id\\\":\\\"\\\",\\\"status\\\":\\\"ignored\\\",\\\"timestamp\\\":\\\"2017-03-22T18:56:25+08:00\\\",\\\"user\\\":\\\"owl\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/alarm/event_note\",\n      \"Calls\": [\n        {\n          \"Id\": 9,\n          \"CurrentPath\": \"/api/v1/alarm/event_note\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/json\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\\n\\t\\t\\t{\\n\\t\\t\\t\\t\\\"event_id\\\": \\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\n\\t\\t\\t\\t\\\"note\\\": \\\"test note\\\",\\n\\t\\t\\t\\t\\\"status\\\": \\\"comment\\\"\\n\\t\\t\\t}\",\n          \"ResponseBody\": \"{\\\"id\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"message\\\":\\\"add note to s_165_cef145900bf4e2a4a0db8b85762b9cdb successfuled\\\"}\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 10,\n          \"CurrentPath\": \"/api/v1/alarm/event_note\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/json\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\\n\\t\\t\\t{\\n\\t\\t\\t\\t\\\"event_id\\\": \\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\n\\t\\t\\t\\t\\\"note\\\": \\\"test note\\\",\\n\\t\\t\\t\\t\\\"status\\\": \\\"ignored\\\",\\n\\t\\t\\t\\t\\\"case_id\\\": \\\"a000001\\\"\\n\\t\\t\\t}\",\n          \"ResponseBody\": \"{\\\"id\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"message\\\":\\\"add note to s_165_cef145900bf4e2a4a0db8b85762b9cdb successfuled\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/alarm/eventcases\",\n      \"Calls\": [\n        {\n          \"Id\": 11,\n          \"CurrentPath\": \"/api/v1/alarm/eventcases\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"event_id\": \"s_165_cef145900bf4e2a4a0db8b85762b9cdb\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"endpoint\\\":\\\"agent2\\\",\\\"metric\\\":\\\"cpu.idle\\\",\\\"func\\\":\\\"all(#1)\\\",\\\"cond\\\":\\\"0 != 66\\\",\\\"note\\\":\\\"測試告警自動更新\\\",\\\"step\\\":300,\\\"current_step\\\":3,\\\"priority\\\":0,\\\"status\\\":\\\"PROBLEM\\\",\\\"timestamp\\\":\\\"2017-03-23T15:51:11+08:00\\\",\\\"update_at\\\":\\\"2016-06-23T05:00:00+08:00\\\",\\\"closed_at\\\":null,\\\"closed_note\\\":\\\"\\\",\\\"user_modified\\\":0,\\\"tpl_creator\\\":\\\"root\\\",\\\"expression_id\\\":0,\\\"strategy_id\\\":165,\\\"template_id\\\":45,\\\"process_note\\\":56603,\\\"process_status\\\":\\\"ignored\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/alarm/events\",\n      \"Calls\": [\n        {\n          \"Id\": 12,\n          \"CurrentPath\": \"/api/v1/alarm/events\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": {\n            \"endTime\": \"1466628960\",\n            \"event_id\": \"s_165_cef145900bf4e2a4a0db8b85762b9cdb\",\n            \"startTime\": \"1466611200\"\n          },\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/x-www-form-urlencoded\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":635166,\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"step\\\":0,\\\"cond\\\":\\\"10.649350649350648 != 66\\\",\\\"status\\\":0,\\\"timestamp\\\":\\\"2016-06-23T04:55:00+08:00\\\"},{\\\"id\\\":635149,\\\"event_caseId\\\":\\\"s_165_cef145900bf4e2a4a0db8b85762b9cdb\\\",\\\"step\\\":0,\\\"cond\\\":\\\"13.486005089058525 != 66\\\",\\\"status\\\":0,\\\"timestamp\\\":\\\"2016-06-23T04:50:00+08:00\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 13,\n          \"CurrentPath\": \"/api/v1/alarm/events\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": {\n            \"event_id\": \"s_322_00f5a68989281d30fbbb647194a09230\",\n            \"limit\": \"2\",\n            \"status\": \"1\"\n          },\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/x-www-form-urlencoded\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":2283581,\\\"event_caseId\\\":\\\"s_322_00f5a68989281d30fbbb647194a09230\\\",\\\"step\\\":0,\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"status\\\":1,\\\"timestamp\\\":\\\"2016-12-08T02:10:00+08:00\\\"},{\\\"id\\\":2229288,\\\"event_caseId\\\":\\\"s_322_00f5a68989281d30fbbb647194a09230\\\",\\\"step\\\":0,\\\"cond\\\":\\\"0.8756834205893638 \\\\u003e 40\\\",\\\"status\\\":1,\\\"timestamp\\\":\\\"2016-12-02T15:43:00+08:00\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 14,\n          \"CurrentPath\": \"/api/v1/alarm/events\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": {\n            \"event_id\": \"s_322_00f5a68989281d30fbbb647194a09230\",\n            \"limit\": \"1\",\n            \"page\": \"0\"\n          },\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/x-www-form-urlencoded\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":2283581,\\\"event_caseId\\\":\\\"s_322_00f5a68989281d30fbbb647194a09230\\\",\\\"step\\\":0,\\\"cond\\\":\\\"0 \\\\u003e 40\\\",\\\"status\\\":1,\\\"timestamp\\\":\\\"2016-12-08T02:10:00+08:00\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 15,\n          \"CurrentPath\": \"/api/v1/alarm/events\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": {\n            \"event_id\": \"s_322_00f5a68989281d30fbbb647194a09230\",\n            \"limit\": \"1\",\n            \"page\": \"1\"\n          },\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"233fdb00f99811e68a5c001500c6ca5a\\\"}\",\n            \"Content-Type\": \" application/x-www-form-urlencoded\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":2283566,\\\"event_caseId\\\":\\\"s_322_00f5a68989281d30fbbb647194a09230\\\",\\\"step\\\":0,\\\"cond\\\":\\\"2.5609807127182493e+17 \\\\u003e 40\\\",\\\"status\\\":0,\\\"timestamp\\\":\\\"2016-12-08T02:07:00+08:00\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/expression.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n\n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n\n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n\n\n    </div>\n\n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n\n                    <p>Production : <strong>/api/v1</strong></p>\n\n                    <p>Staging : <strong>/api/v1</strong></p>\n\n              </div>\n            </div>\n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n\n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/expression</a></li>\n\n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/expression</a></li>\n\n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/expression/5</a></li>\n\n                <li role=\"presentation\"><a href=\"#3top\" role=\"tab\" data-toggle=\"tab\">DELETE : /api/v1/expression/5</a></li>\n\n                <li role=\"presentation\"><a href=\"#4top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/expression</a></li>\n\n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n\n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-0\" class=\"prettyprint\">{&#34;right_value&#34;:&#34;0&#34;,&#34;priority&#34;:2,&#34;pause&#34;:0,&#34;op&#34;:&#34;==&#34;,&#34;note&#34;:&#34;this is a test exp&#34;,&#34;max_step&#34;:3,&#34;func&#34;:&#34;all(#3)&#34;,&#34;expression&#34;:&#34;each(metric=agent.alive endpoint=docker-agent)&#34;,&#34;action&#34;:{&#34;url&#34;:&#34;http://localhost:1234/callback&#34;,&#34;uic&#34;:[&#34;test&#34;],&#34;callback&#34;:1,&#34;before_callback_sms&#34;:1,&#34;before_callback_mail&#34;:0,&#34;after_callback_sms&#34;:1,&#34;after_callback_mail&#34;:0}}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"right_value\\\":\\\"0\\\",\\\"priority\\\":2,\\\"pause\\\":0,\\\"op\\\":\\\"==\\\",\\\"note\\\":\\\"this is a test exp\\\",\\\"max_step\\\":3,\\\"func\\\":\\\"all(#3)\\\",\\\"expression\\\":\\\"each(metric=agent.alive endpoint=docker-agent)\\\",\\\"action\\\":{\\\"url\\\":\\\"http://localhost:1234/callback\\\",\\\"uic\\\":[\\\"test\\\"],\\\"callback\\\":1,\\\"before_callback_sms\\\":1,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":1,\\\"after_callback_mail\\\":0}}\");\n                            document.getElementById('request-body0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">{&#34;message&#34;:&#34;expression created&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"expression created\\\"}\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-1-0\" class=\"prettyprint\">{&#34;right_value&#34;:&#34;0&#34;,&#34;priority&#34;:2,&#34;pause&#34;:1,&#34;op&#34;:&#34;==&#34;,&#34;note&#34;:&#34;this is a test exp&#34;,&#34;max_step&#34;:3,&#34;id&#34;:5,&#34;func&#34;:&#34;all(#3)&#34;,&#34;expression&#34;:&#34;each(metric=agent.alive endpoint=docker-agent)&#34;,&#34;action&#34;:{&#34;url&#34;:&#34;http://localhost:1234/callback&#34;,&#34;uic&#34;:[&#34;test&#34;,&#34;test2&#34;],&#34;callback&#34;:0,&#34;before_callback_sms&#34;:1,&#34;before_callback_mail&#34;:0,&#34;after_callback_sms&#34;:1,&#34;after_callback_mail&#34;:0}}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"right_value\\\":\\\"0\\\",\\\"priority\\\":2,\\\"pause\\\":1,\\\"op\\\":\\\"==\\\",\\\"note\\\":\\\"this is a test exp\\\",\\\"max_step\\\":3,\\\"id\\\":5,\\\"func\\\":\\\"all(#3)\\\",\\\"expression\\\":\\\"each(metric=agent.alive endpoint=docker-agent)\\\",\\\"action\\\":{\\\"url\\\":\\\"http://localhost:1234/callback\\\",\\\"uic\\\":[\\\"test\\\",\\\"test2\\\"],\\\"callback\\\":0,\\\"before_callback_sms\\\":1,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":1,\\\"after_callback_mail\\\":0}}\");\n                            document.getElementById('request-body1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">{&#34;message&#34;:&#34;expression:5 has been updated&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"expression:5 has been updated\\\"}\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">{&#34;action&#34;:{&#34;id&#34;:5,&#34;uic&#34;:&#34;taipei&#34;,&#34;url&#34;:&#34;&#34;,&#34;callback&#34;:0,&#34;before_callback_sms&#34;:0,&#34;before_callback_mail&#34;:0,&#34;after_callback_sms&#34;:0,&#34;after_callback_mail&#34;:0},&#34;expression&#34;:{&#34;id&#34;:5,&#34;expression&#34;:&#34;each(metric=agent.alive endpoint=docker-agent)&#34;,&#34;func&#34;:&#34;all(#3)&#34;,&#34;op&#34;:&#34;==&#34;,&#34;right_value&#34;:&#34;0&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:2,&#34;note&#34;:&#34;this is a test exp&#34;,&#34;action_id&#34;:177,&#34;create_user&#34;:&#34;root&#34;,&#34;pause&#34;:1}}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"action\\\":{\\\"id\\\":5,\\\"uic\\\":\\\"taipei\\\",\\\"url\\\":\\\"\\\",\\\"callback\\\":0,\\\"before_callback_sms\\\":0,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":0,\\\"after_callback_mail\\\":0},\\\"expression\\\":{\\\"id\\\":5,\\\"expression\\\":\\\"each(metric=agent.alive endpoint=docker-agent)\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"note\\\":\\\"this is a test exp\\\",\\\"action_id\\\":177,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":1}}\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"3top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-3-0\">{&#34;message&#34;:&#34;expression:5 has been deleted&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"expression:5 has been deleted\\\"}\");\n                            document.getElementById('response-body-3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"4top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-0\">[{&#34;id&#34;:2,&#34;expression&#34;:&#34;each(metric=? xx=yy)&#34;,&#34;func&#34;:&#34;all(#3)&#34;,&#34;op&#34;:&#34;==&#34;,&#34;right_value&#34;:&#34;0&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:0,&#34;note&#34;:&#34;&#34;,&#34;action_id&#34;:18,&#34;create_user&#34;:&#34;root&#34;,&#34;pause&#34;:0},{&#34;id&#34;:3,&#34;expression&#34;:&#34;each(metric=ss.close.wait endpoint=docker-A)&#34;,&#34;func&#34;:&#34;all(#1)&#34;,&#34;op&#34;:&#34;!=&#34;,&#34;right_value&#34;:&#34;0&#34;,&#34;max_step&#34;:1,&#34;priority&#34;:4,&#34;note&#34;:&#34;boss docker-A 连接数大于10&#34;,&#34;action_id&#34;:91,&#34;create_user&#34;:&#34;root&#34;,&#34;pause&#34;:0},{&#34;id&#34;:4,&#34;expression&#34;:&#34;each(metric=agent.alive endpoint=docker-agent)&#34;,&#34;func&#34;:&#34;all(#3)&#34;,&#34;op&#34;:&#34;==&#34;,&#34;right_value&#34;:&#34;0&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:2,&#34;note&#34;:&#34;this is a test exp&#34;,&#34;action_id&#34;:176,&#34;create_user&#34;:&#34;root&#34;,&#34;pause&#34;:1}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":2,\\\"expression\\\":\\\"each(metric=? xx=yy)\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":3,\\\"priority\\\":0,\\\"note\\\":\\\"\\\",\\\"action_id\\\":18,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":0},{\\\"id\\\":3,\\\"expression\\\":\\\"each(metric=ss.close.wait endpoint=docker-A)\\\",\\\"func\\\":\\\"all(#1)\\\",\\\"op\\\":\\\"!=\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":1,\\\"priority\\\":4,\\\"note\\\":\\\"boss docker-A 连接数大于10\\\",\\\"action_id\\\":91,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":0},{\\\"id\\\":4,\\\"expression\\\":\\\"each(metric=agent.alive endpoint=docker-agent)\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"note\\\":\\\"this is a test exp\\\",\\\"action_id\\\":176,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":1}]\");\n                            document.getElementById('response-body-4-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>limit</td>\n                        <td> 2</td>\n                    </tr>\n\n                    <tr>\n                        <td>page</td>\n                        <td> 1</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-1\">[{&#34;id&#34;:2,&#34;expression&#34;:&#34;each(metric=? xx=yy)&#34;,&#34;func&#34;:&#34;all(#3)&#34;,&#34;op&#34;:&#34;==&#34;,&#34;right_value&#34;:&#34;0&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:0,&#34;note&#34;:&#34;&#34;,&#34;action_id&#34;:18,&#34;create_user&#34;:&#34;root&#34;,&#34;pause&#34;:0},{&#34;id&#34;:3,&#34;expression&#34;:&#34;each(metric=ss.close.wait endpoint=docker-A)&#34;,&#34;func&#34;:&#34;all(#1)&#34;,&#34;op&#34;:&#34;!=&#34;,&#34;right_value&#34;:&#34;0&#34;,&#34;max_step&#34;:1,&#34;priority&#34;:4,&#34;note&#34;:&#34;boss docker-A 连接数大于10&#34;,&#34;action_id&#34;:91,&#34;create_user&#34;:&#34;root&#34;,&#34;pause&#34;:0}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":2,\\\"expression\\\":\\\"each(metric=? xx=yy)\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":3,\\\"priority\\\":0,\\\"note\\\":\\\"\\\",\\\"action_id\\\":18,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":0},{\\\"id\\\":3,\\\"expression\\\":\\\"each(metric=ss.close.wait endpoint=docker-A)\\\",\\\"func\\\":\\\"all(#1)\\\",\\\"op\\\":\\\"!=\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":1,\\\"priority\\\":4,\\\"note\\\":\\\"boss docker-A 连接数大于10\\\",\\\"action_id\\\":91,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":0}]\");\n                            document.getElementById('response-body-4-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>\n"
  },
  {
    "path": "docs/doc/expression.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/expression\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/expression\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"right_value\\\":\\\"0\\\",\\\"priority\\\":2,\\\"pause\\\":0,\\\"op\\\":\\\"==\\\",\\\"note\\\":\\\"this is a test exp\\\",\\\"max_step\\\":3,\\\"func\\\":\\\"all(#3)\\\",\\\"expression\\\":\\\"each(metric=agent.alive endpoint=docker-agent)\\\",\\\"action\\\":{\\\"url\\\":\\\"http://localhost:1234/callback\\\",\\\"uic\\\":[\\\"test\\\"],\\\"callback\\\":1,\\\"before_callback_sms\\\":1,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":1,\\\"after_callback_mail\\\":0}}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"expression created\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/expression\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/expression\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"right_value\\\":\\\"0\\\",\\\"priority\\\":2,\\\"pause\\\":1,\\\"op\\\":\\\"==\\\",\\\"note\\\":\\\"this is a test exp\\\",\\\"max_step\\\":3,\\\"id\\\":5,\\\"func\\\":\\\"all(#3)\\\",\\\"expression\\\":\\\"each(metric=agent.alive endpoint=docker-agent)\\\",\\\"action\\\":{\\\"url\\\":\\\"http://localhost:1234/callback\\\",\\\"uic\\\":[\\\"test\\\",\\\"test2\\\"],\\\"callback\\\":0,\\\"before_callback_sms\\\":1,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":1,\\\"after_callback_mail\\\":0}}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"expression:5 has been updated\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/expression/5\",\n      \"Calls\": [\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/expression/5\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"action\\\":{\\\"id\\\":5,\\\"uic\\\":\\\"taipei\\\",\\\"url\\\":\\\"\\\",\\\"callback\\\":0,\\\"before_callback_sms\\\":0,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":0,\\\"after_callback_mail\\\":0},\\\"expression\\\":{\\\"id\\\":5,\\\"expression\\\":\\\"each(metric=agent.alive endpoint=docker-agent)\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"note\\\":\\\"this is a test exp\\\",\\\"action_id\\\":177,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":1}}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"DELETE\",\n      \"Path\": \"/api/v1/expression/5\",\n      \"Calls\": [\n        {\n          \"Id\": 3,\n          \"CurrentPath\": \"/api/v1/expression/5\",\n          \"MethodType\": \"DELETE\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"expression:5 has been deleted\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/expression\",\n      \"Calls\": [\n        {\n          \"Id\": 4,\n          \"CurrentPath\": \"/api/v1/expression\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":2,\\\"expression\\\":\\\"each(metric=? xx=yy)\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":3,\\\"priority\\\":0,\\\"note\\\":\\\"\\\",\\\"action_id\\\":18,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":0},{\\\"id\\\":3,\\\"expression\\\":\\\"each(metric=ss.close.wait endpoint=docker-A)\\\",\\\"func\\\":\\\"all(#1)\\\",\\\"op\\\":\\\"!=\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":1,\\\"priority\\\":4,\\\"note\\\":\\\"boss docker-A 连接数大于10\\\",\\\"action_id\\\":91,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":0},{\\\"id\\\":4,\\\"expression\\\":\\\"each(metric=agent.alive endpoint=docker-agent)\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"note\\\":\\\"this is a test exp\\\",\\\"action_id\\\":176,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":1}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/expression\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"limit\": \"2\",\n            \"page\": \"1\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":2,\\\"expression\\\":\\\"each(metric=? xx=yy)\\\",\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":3,\\\"priority\\\":0,\\\"note\\\":\\\"\\\",\\\"action_id\\\":18,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":0},{\\\"id\\\":3,\\\"expression\\\":\\\"each(metric=ss.close.wait endpoint=docker-A)\\\",\\\"func\\\":\\\"all(#1)\\\",\\\"op\\\":\\\"!=\\\",\\\"right_value\\\":\\\"0\\\",\\\"max_step\\\":1,\\\"priority\\\":4,\\\"note\\\":\\\"boss docker-A 连接数大于10\\\",\\\"action_id\\\":91,\\\"create_user\\\":\\\"root\\\",\\\"pause\\\":0}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/graph.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n\n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n\n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n\n\n    </div>\n\n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n\n                    <p>Production : <strong>/api/v1</strong></p>\n\n                    <p>Staging : <strong>/api/v1</strong></p>\n\n              </div>\n            </div>\n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n\n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/graph/endpoint</a></li>\n\n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/graph/endpoint_counter</a></li>\n\n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/graph/history</a></li>\n\n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n\n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=test1; sig=d4f71cba377911e699d60242ac110010\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">400</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">{&#34;error&#34;:&#34;q is missing&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"q is missing\\\"}\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">401</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=test1; sig=d4f71cba377911e699d60242ac110010\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>q</td>\n                        <td> a.&#43;</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-2\">[{&#34;endpoint&#34;:&#34;docker-agent&#34;,&#34;id&#34;:7},{&#34;endpoint&#34;:&#34;docker-task&#34;,&#34;id&#34;:6},{&#34;endpoint&#34;:&#34;graph&#34;,&#34;id&#34;:3},{&#34;endpoint&#34;:&#34;nodata&#34;,&#34;id&#34;:920},{&#34;endpoint&#34;:&#34;task&#34;,&#34;id&#34;:5}]</pre>\n                <script>\n\n                    var responseHeader ={\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"endpoint\\\":\\\"docker-agent\\\",\\\"id\\\":7},{\\\"endpoint\\\":\\\"docker-task\\\",\\\"id\\\":6},{\\\"endpoint\\\":\\\"graph\\\",\\\"id\\\":3},{\\\"endpoint\\\":\\\"nodata\\\",\\\"id\\\":920},{\\\"endpoint\\\":\\\"task\\\",\\\"id\\\":5}]\");\n                            document.getElementById('response-body-0-2').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>limit</td>\n                        <td> 10</td>\n                    </tr>\n\n                    <tr>\n                        <td>q</td>\n                        <td> .&#43;</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-3\">[{&#34;endpoint&#34;:&#34;docker-A&#34;,&#34;id&#34;:244525914},{&#34;endpoint&#34;:&#34;docker-B&#34;,&#34;id&#34;:12675145},{&#34;endpoint&#34;:&#34;docker-C&#34;,&#34;id&#34;:12683936},{&#34;endpoint&#34;:&#34;docker-D&#34;,&#34;id&#34;:12681439},{&#34;endpoint&#34;:&#34;docker-D&#34;,&#34;id&#34;:12676363},{&#34;endpoint&#34;:&#34;docker-E&#34;,&#34;id&#34;:12681715},{&#34;endpoint&#34;:&#34;docker-F&#34;,&#34;id&#34;:12678421},{&#34;endpoint&#34;:&#34;docker-F&#34;,&#34;id&#34;:12676879},{&#34;endpoint&#34;:&#34;docker-F&#34;,&#34;id&#34;:12675447},{&#34;endpoint&#34;:&#34;bgp-bj-058-083-161-110&#34;,&#34;id&#34;:12679349}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"endpoint\\\":\\\"docker-A\\\",\\\"id\\\":244525914},{\\\"endpoint\\\":\\\"docker-B\\\",\\\"id\\\":12675145},{\\\"endpoint\\\":\\\"docker-C\\\",\\\"id\\\":12683936},{\\\"endpoint\\\":\\\"docker-D\\\",\\\"id\\\":12681439},{\\\"endpoint\\\":\\\"docker-D\\\",\\\"id\\\":12676363},{\\\"endpoint\\\":\\\"docker-E\\\",\\\"id\\\":12681715},{\\\"endpoint\\\":\\\"docker-F\\\",\\\"id\\\":12678421},{\\\"endpoint\\\":\\\"docker-F\\\",\\\"id\\\":12676879},{\\\"endpoint\\\":\\\"docker-F\\\",\\\"id\\\":12675447},{\\\"endpoint\\\":\\\"bgp-bj-058-083-161-110\\\",\\\"id\\\":12679349}]\");\n                            document.getElementById('response-body-0-3').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=test1; sig=d4f71cba377911e699d60242ac110010\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">400</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">{&#34;error&#34;:&#34;eid is missing&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"eid is missing\\\"}\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=test1; sig=d4f71cba377911e699d60242ac110010\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>eid</td>\n                        <td> 6,7</td>\n                    </tr>\n\n                    <tr>\n                        <td>metricQuery</td>\n                        <td> disk.&#43;</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-1\">[&#34;disk.io.avgqu-sz/device=sda&#34;,&#34;disk.io.ios_in_progress/device=sda&#34;,&#34;disk.io.msec_read/device=sda&#34;,&#34;disk.io.read_requests/device=sda&#34;,&#34;disk.io.read_sectors/device=sda&#34;,&#34;disk.io.write_bytes/device=sda&#34;,&#34;disk.io.write_merged/device=sda&#34;,&#34;disk.io.msec_write/device=sda&#34;,&#34;disk.io.read_merged/device=sda&#34;,&#34;disk.io.svctm/device=sda&#34;,&#34;disk.io.util/device=sda&#34;,&#34;disk.io.avgrq_sz/device=sda&#34;,&#34;disk.io.msec_weighted_total/device=sda&#34;,&#34;disk.io.await/device=sda&#34;,&#34;disk.io.msec_total/device=sda&#34;,&#34;disk.io.read_bytes/device=sda&#34;,&#34;disk.io.write_requests/device=sda&#34;,&#34;disk.io.write_sectors/device=sda&#34;]</pre>\n                <script>\n\n                    var responseHeader ={\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[\\\"disk.io.avgqu-sz/device=sda\\\",\\\"disk.io.ios_in_progress/device=sda\\\",\\\"disk.io.msec_read/device=sda\\\",\\\"disk.io.read_requests/device=sda\\\",\\\"disk.io.read_sectors/device=sda\\\",\\\"disk.io.write_bytes/device=sda\\\",\\\"disk.io.write_merged/device=sda\\\",\\\"disk.io.msec_write/device=sda\\\",\\\"disk.io.read_merged/device=sda\\\",\\\"disk.io.svctm/device=sda\\\",\\\"disk.io.util/device=sda\\\",\\\"disk.io.avgrq_sz/device=sda\\\",\\\"disk.io.msec_weighted_total/device=sda\\\",\\\"disk.io.await/device=sda\\\",\\\"disk.io.msec_total/device=sda\\\",\\\"disk.io.read_bytes/device=sda\\\",\\\"disk.io.write_requests/device=sda\\\",\\\"disk.io.write_sectors/device=sda\\\"]\");\n                            document.getElementById('response-body-1-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>eid</td>\n                        <td> 244525914,12675145,12683936,12681439,12676363,12681715,12678421,12676879,12675447,12679349</td>\n                    </tr>\n\n                    <tr>\n                        <td>limit</td>\n                        <td> 3</td>\n                    </tr>\n\n                    <tr>\n                        <td>metricQuery</td>\n                        <td> disk.&#43;</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-2\">[&#34;disk.io.write_sectors/device=sdh&#34;,&#34;disk.device.size/device=sdm&#34;,&#34;disk.io.ios_in_progress/device=sdj&#34;]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[\\\"disk.io.write_sectors/device=sdh\\\",\\\"disk.device.size/device=sdm\\\",\\\"disk.io.ios_in_progress/device=sdj\\\"]\");\n                            document.getElementById('response-body-1-2').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-0\" class=\"prettyprint\">{&#34;step&#34;:60,&#34;start_time&#34;:1481854596,&#34;hostnames&#34;:[&#34;docker-a&#34;,&#34;docker-b&#34;,&#34;docker-c&#34;],&#34;end_time&#34;:1481858193,&#34;counters&#34;:[&#34;cpu.idle&#34;,&#34;cpu.iowait&#34;],&#34;consol_fun&#34;:&#34;AVERAGE&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"step\\\":60,\\\"start_time\\\":1481854596,\\\"hostnames\\\":[\\\"docker-a\\\",\\\"docker-b\\\",\\\"docker-c\\\"],\\\"end_time\\\":1481858193,\\\"counters\\\":[\\\"cpu.idle\\\",\\\"cpu.iowait\\\"],\\\"consol_fun\\\":\\\"AVERAGE\\\"}\");\n                            document.getElementById('request-body2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">[{&#34;endpoint&#34;:&#34;docker-a&#34;,&#34;counter&#34;:&#34;cpu.idle&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;Values&#34;:[{&#34;timestamp&#34;:1481854620,&#34;value&#34;:98.154506},{&#34;timestamp&#34;:1481854680,&#34;value&#34;:97.864161},{&#34;timestamp&#34;:1481854740,&#34;value&#34;:97.521368},{&#34;timestamp&#34;:1481854800,&#34;value&#34;:97.587247},{&#34;timestamp&#34;:1481854860,&#34;value&#34;:97.440273},{&#34;timestamp&#34;:1481854920,&#34;value&#34;:97.914006},{&#34;timestamp&#34;:1481854980,&#34;value&#34;:97.223409},{&#34;timestamp&#34;:1481855040,&#34;value&#34;:98.029135},{&#34;timestamp&#34;:1481855100,&#34;value&#34;:97.614991},{&#34;timestamp&#34;:1481855160,&#34;value&#34;:97.565143},{&#34;timestamp&#34;:1481855220,&#34;value&#34;:97.070064},{&#34;timestamp&#34;:1481855280,&#34;value&#34;:98.726115},{&#34;timestamp&#34;:1481855340,&#34;value&#34;:98.720137},{&#34;timestamp&#34;:1481855400,&#34;value&#34;:98.205128},{&#34;timestamp&#34;:1481855460,&#34;value&#34;:97.700170},{&#34;timestamp&#34;:1481855520,&#34;value&#34;:97.780623},{&#34;timestamp&#34;:1481855580,&#34;value&#34;:97.379725},{&#34;timestamp&#34;:1481855640,&#34;value&#34;:98.034188},{&#34;timestamp&#34;:1481855700,&#34;value&#34;:98.246364},{&#34;timestamp&#34;:1481855760,&#34;value&#34;:98.372591},{&#34;timestamp&#34;:1481855820,&#34;value&#34;:98.152921},{&#34;timestamp&#34;:1481855880,&#34;value&#34;:97.914006},{&#34;timestamp&#34;:1481855940,&#34;value&#34;:95.592048},{&#34;timestamp&#34;:1481856000,&#34;value&#34;:94.115120},{&#34;timestamp&#34;:1481856060,&#34;value&#34;:97.596567},{&#34;timestamp&#34;:1481856120,&#34;value&#34;:97.501077},{&#34;timestamp&#34;:1481856180,&#34;value&#34;:96.374622},{&#34;timestamp&#34;:1481856240,&#34;value&#34;:89.570815},{&#34;timestamp&#34;:1481856300,&#34;value&#34;:96.410035},{&#34;timestamp&#34;:1481856360,&#34;value&#34;:97.567222},{&#34;timestamp&#34;:1481856420,&#34;value&#34;:97.252040},{&#34;timestamp&#34;:1481856480,&#34;value&#34;:95.356836},{&#34;timestamp&#34;:1481856540,&#34;value&#34;:97.330508},{&#34;timestamp&#34;:1481856600,&#34;value&#34;:96.999571},{&#34;timestamp&#34;:1481856660,&#34;value&#34;:97.278912},{&#34;timestamp&#34;:1481856720,&#34;value&#34;:97.229327},{&#34;timestamp&#34;:1481856780,&#34;value&#34;:97.212693},{&#34;timestamp&#34;:1481856840,&#34;value&#34;:96.503198},{&#34;timestamp&#34;:1481856900,&#34;value&#34;:96.790757},{&#34;timestamp&#34;:1481856960,&#34;value&#34;:98.121264},{&#34;timestamp&#34;:1481857020,&#34;value&#34;:98.550725},{&#34;timestamp&#34;:1481857080,&#34;value&#34;:97.548387},{&#34;timestamp&#34;:1481857140,&#34;value&#34;:98.466127},{&#34;timestamp&#34;:1481857200,&#34;value&#34;:97.900600},{&#34;timestamp&#34;:1481857260,&#34;value&#34;:97.985426},{&#34;timestamp&#34;:1481857320,&#34;value&#34;:97.357204},{&#34;timestamp&#34;:1481857380,&#34;value&#34;:97.086547},{&#34;timestamp&#34;:1481857440,&#34;value&#34;:98.770144},{&#34;timestamp&#34;:1481857500,&#34;value&#34;:97.727273},{&#34;timestamp&#34;:1481857560,&#34;value&#34;:98.595147},{&#34;timestamp&#34;:1481857620,&#34;value&#34;:97.867804},{&#34;timestamp&#34;:1481857680,&#34;value&#34;:98.128456},{&#34;timestamp&#34;:1481857740,&#34;value&#34;:97.886729},{&#34;timestamp&#34;:1481857800,&#34;value&#34;:95.969453},{&#34;timestamp&#34;:1481857860,&#34;value&#34;:97.134303},{&#34;timestamp&#34;:1481857920,&#34;value&#34;:98.033348},{&#34;timestamp&#34;:1481857980,&#34;value&#34;:96.511628},{&#34;timestamp&#34;:1481858040,&#34;value&#34;:96.522112},{&#34;timestamp&#34;:1481858100,&#34;value&#34;:97.490430},{&#34;timestamp&#34;:1481858160,&#34;value&#34;:96.958012}]},{&#34;endpoint&#34;:&#34;docker-a&#34;,&#34;counter&#34;:&#34;cpu.iowait&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;Values&#34;:[{&#34;timestamp&#34;:1481854620,&#34;value&#34;:0.815451},{&#34;timestamp&#34;:1481854680,&#34;value&#34;:0.598035},{&#34;timestamp&#34;:1481854740,&#34;value&#34;:1.239316},{&#34;timestamp&#34;:1481854800,&#34;value&#34;:0.775528},{&#34;timestamp&#34;:1481854860,&#34;value&#34;:0.895904},{&#34;timestamp&#34;:1481854920,&#34;value&#34;:0.893997},{&#34;timestamp&#34;:1481854980,&#34;value&#34;:0.811619},{&#34;timestamp&#34;:1481855040,&#34;value&#34;:0.728363},{&#34;timestamp&#34;:1481855100,&#34;value&#34;:0.425894},{&#34;timestamp&#34;:1481855160,&#34;value&#34;:0.768902},{&#34;timestamp&#34;:1481855220,&#34;value&#34;:1.443737},{&#34;timestamp&#34;:1481855280,&#34;value&#34;:0.297240},{&#34;timestamp&#34;:1481855340,&#34;value&#34;:0.213311},{&#34;timestamp&#34;:1481855400,&#34;value&#34;:0.512821},{&#34;timestamp&#34;:1481855460,&#34;value&#34;:1.022147},{&#34;timestamp&#34;:1481855520,&#34;value&#34;:0.810926},{&#34;timestamp&#34;:1481855580,&#34;value&#34;:0.515464},{&#34;timestamp&#34;:1481855640,&#34;value&#34;:0.555556},{&#34;timestamp&#34;:1481855700,&#34;value&#34;:0.470488},{&#34;timestamp&#34;:1481855760,&#34;value&#34;:0.428266},{&#34;timestamp&#34;:1481855820,&#34;value&#34;:0.386598},{&#34;timestamp&#34;:1481855880,&#34;value&#34;:0.638570},{&#34;timestamp&#34;:1481855940,&#34;value&#34;:0.432152},{&#34;timestamp&#34;:1481856000,&#34;value&#34;:0.730241},{&#34;timestamp&#34;:1481856060,&#34;value&#34;:0.643777},{&#34;timestamp&#34;:1481856120,&#34;value&#34;:0.603188},{&#34;timestamp&#34;:1481856180,&#34;value&#34;:1.035822},{&#34;timestamp&#34;:1481856240,&#34;value&#34;:8.927039},{&#34;timestamp&#34;:1481856300,&#34;value&#34;:0.605536},{&#34;timestamp&#34;:1481856360,&#34;value&#34;:0.341443},{&#34;timestamp&#34;:1481856420,&#34;value&#34;:0.343495},{&#34;timestamp&#34;:1481856480,&#34;value&#34;:0.601892},{&#34;timestamp&#34;:1481856540,&#34;value&#34;:0.466102},{&#34;timestamp&#34;:1481856600,&#34;value&#34;:0.557222},{&#34;timestamp&#34;:1481856660,&#34;value&#34;:0.382653},{&#34;timestamp&#34;:1481856720,&#34;value&#34;:0.554135},{&#34;timestamp&#34;:1481856780,&#34;value&#34;:0.428816},{&#34;timestamp&#34;:1481856840,&#34;value&#34;:1.151386},{&#34;timestamp&#34;:1481856900,&#34;value&#34;:0.556269},{&#34;timestamp&#34;:1481856960,&#34;value&#34;:0.469684},{&#34;timestamp&#34;:1481857020,&#34;value&#34;:0.298380},{&#34;timestamp&#34;:1481857080,&#34;value&#34;:0.903226},{&#34;timestamp&#34;:1481857140,&#34;value&#34;:0.426076},{&#34;timestamp&#34;:1481857200,&#34;value&#34;:0.771208},{&#34;timestamp&#34;:1481857260,&#34;value&#34;:1.071582},{&#34;timestamp&#34;:1481857320,&#34;value&#34;:1.278772},{&#34;timestamp&#34;:1481857380,&#34;value&#34;:0.642674},{&#34;timestamp&#34;:1481857440,&#34;value&#34;:0.212044},{&#34;timestamp&#34;:1481857500,&#34;value&#34;:0.686106},{&#34;timestamp&#34;:1481857560,&#34;value&#34;:0.425713},{&#34;timestamp&#34;:1481857620,&#34;value&#34;:0.810235},{&#34;timestamp&#34;:1481857680,&#34;value&#34;:0.765632},{&#34;timestamp&#34;:1481857740,&#34;value&#34;:0.380389},{&#34;timestamp&#34;:1481857800,&#34;value&#34;:0.296988},{&#34;timestamp&#34;:1481857860,&#34;value&#34;:0.855432},{&#34;timestamp&#34;:1481857920,&#34;value&#34;:0.470286},{&#34;timestamp&#34;:1481857980,&#34;value&#34;:1.248923},{&#34;timestamp&#34;:1481858040,&#34;value&#34;:1.631602},{&#34;timestamp&#34;:1481858100,&#34;value&#34;:1.531263},{&#34;timestamp&#34;:1481858160,&#34;value&#34;:0.599829}]},{&#34;endpoint&#34;:&#34;docker-b&#34;,&#34;counter&#34;:&#34;cpu.idle&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;Values&#34;:[{&#34;timestamp&#34;:1481854620,&#34;value&#34;:93.811775},{&#34;timestamp&#34;:1481854680,&#34;value&#34;:94.150538},{&#34;timestamp&#34;:1481854740,&#34;value&#34;:94.991438},{&#34;timestamp&#34;:1481854800,&#34;value&#34;:93.287435},{&#34;timestamp&#34;:1481854860,&#34;value&#34;:96.642584},{&#34;timestamp&#34;:1481854920,&#34;value&#34;:98.207426},{&#34;timestamp&#34;:1481854980,&#34;value&#34;:94.801875},{&#34;timestamp&#34;:1481855040,&#34;value&#34;:97.827939},{&#34;timestamp&#34;:1481855100,&#34;value&#34;:94.439692},{&#34;timestamp&#34;:1481855160,&#34;value&#34;:98.292787},{&#34;timestamp&#34;:1481855220,&#34;value&#34;:95.027624},{&#34;timestamp&#34;:1481855280,&#34;value&#34;:98.218074},{&#34;timestamp&#34;:1481855340,&#34;value&#34;:97.402044},{&#34;timestamp&#34;:1481855400,&#34;value&#34;:94.368601},{&#34;timestamp&#34;:1481855460,&#34;value&#34;:94.772631},{&#34;timestamp&#34;:1481855520,&#34;value&#34;:93.992331},{&#34;timestamp&#34;:1481855580,&#34;value&#34;:94.939446},{&#34;timestamp&#34;:1481855640,&#34;value&#34;:97.780623},{&#34;timestamp&#34;:1481855700,&#34;value&#34;:97.860505},{&#34;timestamp&#34;:1481855760,&#34;value&#34;:92.765411},{&#34;timestamp&#34;:1481855820,&#34;value&#34;:98.029979},{&#34;timestamp&#34;:1481855880,&#34;value&#34;:94.523502},{&#34;timestamp&#34;:1481855940,&#34;value&#34;:94.102564},{&#34;timestamp&#34;:1481856000,&#34;value&#34;:94.965870},{&#34;timestamp&#34;:1481856060,&#34;value&#34;:94.382979},{&#34;timestamp&#34;:1481856120,&#34;value&#34;:93.336181},{&#34;timestamp&#34;:1481856180,&#34;value&#34;:97.988875},{&#34;timestamp&#34;:1481856240,&#34;value&#34;:94.401709},{&#34;timestamp&#34;:1481856300,&#34;value&#34;:94.619983},{&#34;timestamp&#34;:1481856360,&#34;value&#34;:94.916702},{&#34;timestamp&#34;:1481856420,&#34;value&#34;:94.089733},{&#34;timestamp&#34;:1481856480,&#34;value&#34;:94.475375},{&#34;timestamp&#34;:1481856540,&#34;value&#34;:93.576017},{&#34;timestamp&#34;:1481856600,&#34;value&#34;:94.010195},{&#34;timestamp&#34;:1481856660,&#34;value&#34;:94.137783},{&#34;timestamp&#34;:1481856720,&#34;value&#34;:95.264505},{&#34;timestamp&#34;:1481856780,&#34;value&#34;:96.879008},{&#34;timestamp&#34;:1481856840,&#34;value&#34;:96.387590},{&#34;timestamp&#34;:1481856900,&#34;value&#34;:93.830334},{&#34;timestamp&#34;:1481856960,&#34;value&#34;:96.282051},{&#34;timestamp&#34;:1481857020,&#34;value&#34;:94.173093},{&#34;timestamp&#34;:1481857080,&#34;value&#34;:95.382642},{&#34;timestamp&#34;:1481857140,&#34;value&#34;:94.107452},{&#34;timestamp&#34;:1481857200,&#34;value&#34;:93.611584},{&#34;timestamp&#34;:1481857260,&#34;value&#34;:97.053800},{&#34;timestamp&#34;:1481857320,&#34;value&#34;:94.404101},{&#34;timestamp&#34;:1481857380,&#34;value&#34;:94.449189},{&#34;timestamp&#34;:1481857440,&#34;value&#34;:98.286938},{&#34;timestamp&#34;:1481857500,&#34;value&#34;:93.720632},{&#34;timestamp&#34;:1481857560,&#34;value&#34;:93.669803},{&#34;timestamp&#34;:1481857620,&#34;value&#34;:93.865294},{&#34;timestamp&#34;:1481857680,&#34;value&#34;:94.498934},{&#34;timestamp&#34;:1481857740,&#34;value&#34;:94.610778},{&#34;timestamp&#34;:1481857800,&#34;value&#34;:93.929029},{&#34;timestamp&#34;:1481857860,&#34;value&#34;:97.827939},{&#34;timestamp&#34;:1481857920,&#34;value&#34;:97.768240},{&#34;timestamp&#34;:1481857980,&#34;value&#34;:91.079014},{&#34;timestamp&#34;:1481858040,&#34;value&#34;:97.854998},{&#34;timestamp&#34;:1481858100,&#34;value&#34;:93.399482},{&#34;timestamp&#34;:1481858160,&#34;value&#34;:94.014536}]},{&#34;endpoint&#34;:&#34;docker-b&#34;,&#34;counter&#34;:&#34;cpu.iowait&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;Values&#34;:[{&#34;timestamp&#34;:1481854620,&#34;value&#34;:0.171895},{&#34;timestamp&#34;:1481854680,&#34;value&#34;:0.645161},{&#34;timestamp&#34;:1481854740,&#34;value&#34;:0.470890},{&#34;timestamp&#34;:1481854800,&#34;value&#34;:0.731497},{&#34;timestamp&#34;:1481854860,&#34;value&#34;:0.594985},{&#34;timestamp&#34;:1481854920,&#34;value&#34;:0.256082},{&#34;timestamp&#34;:1481854980,&#34;value&#34;:0.340861},{&#34;timestamp&#34;:1481855040,&#34;value&#34;:0.255537},{&#34;timestamp&#34;:1481855100,&#34;value&#34;:0.684346},{&#34;timestamp&#34;:1481855160,&#34;value&#34;:0.384123},{&#34;timestamp&#34;:1481855220,&#34;value&#34;:0.084998},{&#34;timestamp&#34;:1481855280,&#34;value&#34;:0.466695},{&#34;timestamp&#34;:1481855340,&#34;value&#34;:1.192504},{&#34;timestamp&#34;:1481855400,&#34;value&#34;:0.511945},{&#34;timestamp&#34;:1481855460,&#34;value&#34;:0.594985},{&#34;timestamp&#34;:1481855520,&#34;value&#34;:0.383468},{&#34;timestamp&#34;:1481855580,&#34;value&#34;:1.038062},{&#34;timestamp&#34;:1481855640,&#34;value&#34;:0.981647},{&#34;timestamp&#34;:1481855700,&#34;value&#34;:0.599059},{&#34;timestamp&#34;:1481855760,&#34;value&#34;:0.770548},{&#34;timestamp&#34;:1481855820,&#34;value&#34;:0.428266},{&#34;timestamp&#34;:1481855880,&#34;value&#34;:0.301854},{&#34;timestamp&#34;:1481855940,&#34;value&#34;:0.598291},{&#34;timestamp&#34;:1481856000,&#34;value&#34;:0.853242},{&#34;timestamp&#34;:1481856060,&#34;value&#34;:0.723404},{&#34;timestamp&#34;:1481856120,&#34;value&#34;:1.025203},{&#34;timestamp&#34;:1481856180,&#34;value&#34;:0.470689},{&#34;timestamp&#34;:1481856240,&#34;value&#34;:0.213675},{&#34;timestamp&#34;:1481856300,&#34;value&#34;:0.768574},{&#34;timestamp&#34;:1481856360,&#34;value&#34;:0.256301},{&#34;timestamp&#34;:1481856420,&#34;value&#34;:0.388266},{&#34;timestamp&#34;:1481856480,&#34;value&#34;:0.342612},{&#34;timestamp&#34;:1481856540,&#34;value&#34;:0.813704},{&#34;timestamp&#34;:1481856600,&#34;value&#34;:0.594732},{&#34;timestamp&#34;:1481856660,&#34;value&#34;:0.684638},{&#34;timestamp&#34;:1481856720,&#34;value&#34;:1.535836},{&#34;timestamp&#34;:1481856780,&#34;value&#34;:0.256520},{&#34;timestamp&#34;:1481856840,&#34;value&#34;:0.382490},{&#34;timestamp&#34;:1481856900,&#34;value&#34;:1.028278},{&#34;timestamp&#34;:1481856960,&#34;value&#34;:1.025641},{&#34;timestamp&#34;:1481857020,&#34;value&#34;:0.642674},{&#34;timestamp&#34;:1481857080,&#34;value&#34;:0.726806},{&#34;timestamp&#34;:1481857140,&#34;value&#34;:0.649913},{&#34;timestamp&#34;:1481857200,&#34;value&#34;:0.809199},{&#34;timestamp&#34;:1481857260,&#34;value&#34;:0.256191},{&#34;timestamp&#34;:1481857320,&#34;value&#34;:0.512601},{&#34;timestamp&#34;:1481857380,&#34;value&#34;:0.597780},{&#34;timestamp&#34;:1481857440,&#34;value&#34;:0.342612},{&#34;timestamp&#34;:1481857500,&#34;value&#34;:1.196070},{&#34;timestamp&#34;:1481857560,&#34;value&#34;:0.983747},{&#34;timestamp&#34;:1481857620,&#34;value&#34;:0.900901},{&#34;timestamp&#34;:1481857680,&#34;value&#34;:0.639659},{&#34;timestamp&#34;:1481857740,&#34;value&#34;:0.641574},{&#34;timestamp&#34;:1481857800,&#34;value&#34;:0.598546},{&#34;timestamp&#34;:1481857860,&#34;value&#34;:0.425894},{&#34;timestamp&#34;:1481857920,&#34;value&#34;:0.729614},{&#34;timestamp&#34;:1481857980,&#34;value&#34;:0.339847},{&#34;timestamp&#34;:1481858040,&#34;value&#34;:0.686401},{&#34;timestamp&#34;:1481858100,&#34;value&#34;:0.560828},{&#34;timestamp&#34;:1481858160,&#34;value&#34;:0.513040}]},{&#34;endpoint&#34;:&#34;docker-c&#34;,&#34;counter&#34;:&#34;cpu.idle&#34;,&#34;dstype&#34;:&#34;&#34;,&#34;step&#34;:0,&#34;Values&#34;:[]},{&#34;endpoint&#34;:&#34;docker-c&#34;,&#34;counter&#34;:&#34;cpu.iowait&#34;,&#34;dstype&#34;:&#34;&#34;,&#34;step&#34;:0,&#34;Values&#34;:[]}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"endpoint\\\":\\\"docker-a\\\",\\\"counter\\\":\\\"cpu.idle\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"Values\\\":[{\\\"timestamp\\\":1481854620,\\\"value\\\":98.154506},{\\\"timestamp\\\":1481854680,\\\"value\\\":97.864161},{\\\"timestamp\\\":1481854740,\\\"value\\\":97.521368},{\\\"timestamp\\\":1481854800,\\\"value\\\":97.587247},{\\\"timestamp\\\":1481854860,\\\"value\\\":97.440273},{\\\"timestamp\\\":1481854920,\\\"value\\\":97.914006},{\\\"timestamp\\\":1481854980,\\\"value\\\":97.223409},{\\\"timestamp\\\":1481855040,\\\"value\\\":98.029135},{\\\"timestamp\\\":1481855100,\\\"value\\\":97.614991},{\\\"timestamp\\\":1481855160,\\\"value\\\":97.565143},{\\\"timestamp\\\":1481855220,\\\"value\\\":97.070064},{\\\"timestamp\\\":1481855280,\\\"value\\\":98.726115},{\\\"timestamp\\\":1481855340,\\\"value\\\":98.720137},{\\\"timestamp\\\":1481855400,\\\"value\\\":98.205128},{\\\"timestamp\\\":1481855460,\\\"value\\\":97.700170},{\\\"timestamp\\\":1481855520,\\\"value\\\":97.780623},{\\\"timestamp\\\":1481855580,\\\"value\\\":97.379725},{\\\"timestamp\\\":1481855640,\\\"value\\\":98.034188},{\\\"timestamp\\\":1481855700,\\\"value\\\":98.246364},{\\\"timestamp\\\":1481855760,\\\"value\\\":98.372591},{\\\"timestamp\\\":1481855820,\\\"value\\\":98.152921},{\\\"timestamp\\\":1481855880,\\\"value\\\":97.914006},{\\\"timestamp\\\":1481855940,\\\"value\\\":95.592048},{\\\"timestamp\\\":1481856000,\\\"value\\\":94.115120},{\\\"timestamp\\\":1481856060,\\\"value\\\":97.596567},{\\\"timestamp\\\":1481856120,\\\"value\\\":97.501077},{\\\"timestamp\\\":1481856180,\\\"value\\\":96.374622},{\\\"timestamp\\\":1481856240,\\\"value\\\":89.570815},{\\\"timestamp\\\":1481856300,\\\"value\\\":96.410035},{\\\"timestamp\\\":1481856360,\\\"value\\\":97.567222},{\\\"timestamp\\\":1481856420,\\\"value\\\":97.252040},{\\\"timestamp\\\":1481856480,\\\"value\\\":95.356836},{\\\"timestamp\\\":1481856540,\\\"value\\\":97.330508},{\\\"timestamp\\\":1481856600,\\\"value\\\":96.999571},{\\\"timestamp\\\":1481856660,\\\"value\\\":97.278912},{\\\"timestamp\\\":1481856720,\\\"value\\\":97.229327},{\\\"timestamp\\\":1481856780,\\\"value\\\":97.212693},{\\\"timestamp\\\":1481856840,\\\"value\\\":96.503198},{\\\"timestamp\\\":1481856900,\\\"value\\\":96.790757},{\\\"timestamp\\\":1481856960,\\\"value\\\":98.121264},{\\\"timestamp\\\":1481857020,\\\"value\\\":98.550725},{\\\"timestamp\\\":1481857080,\\\"value\\\":97.548387},{\\\"timestamp\\\":1481857140,\\\"value\\\":98.466127},{\\\"timestamp\\\":1481857200,\\\"value\\\":97.900600},{\\\"timestamp\\\":1481857260,\\\"value\\\":97.985426},{\\\"timestamp\\\":1481857320,\\\"value\\\":97.357204},{\\\"timestamp\\\":1481857380,\\\"value\\\":97.086547},{\\\"timestamp\\\":1481857440,\\\"value\\\":98.770144},{\\\"timestamp\\\":1481857500,\\\"value\\\":97.727273},{\\\"timestamp\\\":1481857560,\\\"value\\\":98.595147},{\\\"timestamp\\\":1481857620,\\\"value\\\":97.867804},{\\\"timestamp\\\":1481857680,\\\"value\\\":98.128456},{\\\"timestamp\\\":1481857740,\\\"value\\\":97.886729},{\\\"timestamp\\\":1481857800,\\\"value\\\":95.969453},{\\\"timestamp\\\":1481857860,\\\"value\\\":97.134303},{\\\"timestamp\\\":1481857920,\\\"value\\\":98.033348},{\\\"timestamp\\\":1481857980,\\\"value\\\":96.511628},{\\\"timestamp\\\":1481858040,\\\"value\\\":96.522112},{\\\"timestamp\\\":1481858100,\\\"value\\\":97.490430},{\\\"timestamp\\\":1481858160,\\\"value\\\":96.958012}]},{\\\"endpoint\\\":\\\"docker-a\\\",\\\"counter\\\":\\\"cpu.iowait\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"Values\\\":[{\\\"timestamp\\\":1481854620,\\\"value\\\":0.815451},{\\\"timestamp\\\":1481854680,\\\"value\\\":0.598035},{\\\"timestamp\\\":1481854740,\\\"value\\\":1.239316},{\\\"timestamp\\\":1481854800,\\\"value\\\":0.775528},{\\\"timestamp\\\":1481854860,\\\"value\\\":0.895904},{\\\"timestamp\\\":1481854920,\\\"value\\\":0.893997},{\\\"timestamp\\\":1481854980,\\\"value\\\":0.811619},{\\\"timestamp\\\":1481855040,\\\"value\\\":0.728363},{\\\"timestamp\\\":1481855100,\\\"value\\\":0.425894},{\\\"timestamp\\\":1481855160,\\\"value\\\":0.768902},{\\\"timestamp\\\":1481855220,\\\"value\\\":1.443737},{\\\"timestamp\\\":1481855280,\\\"value\\\":0.297240},{\\\"timestamp\\\":1481855340,\\\"value\\\":0.213311},{\\\"timestamp\\\":1481855400,\\\"value\\\":0.512821},{\\\"timestamp\\\":1481855460,\\\"value\\\":1.022147},{\\\"timestamp\\\":1481855520,\\\"value\\\":0.810926},{\\\"timestamp\\\":1481855580,\\\"value\\\":0.515464},{\\\"timestamp\\\":1481855640,\\\"value\\\":0.555556},{\\\"timestamp\\\":1481855700,\\\"value\\\":0.470488},{\\\"timestamp\\\":1481855760,\\\"value\\\":0.428266},{\\\"timestamp\\\":1481855820,\\\"value\\\":0.386598},{\\\"timestamp\\\":1481855880,\\\"value\\\":0.638570},{\\\"timestamp\\\":1481855940,\\\"value\\\":0.432152},{\\\"timestamp\\\":1481856000,\\\"value\\\":0.730241},{\\\"timestamp\\\":1481856060,\\\"value\\\":0.643777},{\\\"timestamp\\\":1481856120,\\\"value\\\":0.603188},{\\\"timestamp\\\":1481856180,\\\"value\\\":1.035822},{\\\"timestamp\\\":1481856240,\\\"value\\\":8.927039},{\\\"timestamp\\\":1481856300,\\\"value\\\":0.605536},{\\\"timestamp\\\":1481856360,\\\"value\\\":0.341443},{\\\"timestamp\\\":1481856420,\\\"value\\\":0.343495},{\\\"timestamp\\\":1481856480,\\\"value\\\":0.601892},{\\\"timestamp\\\":1481856540,\\\"value\\\":0.466102},{\\\"timestamp\\\":1481856600,\\\"value\\\":0.557222},{\\\"timestamp\\\":1481856660,\\\"value\\\":0.382653},{\\\"timestamp\\\":1481856720,\\\"value\\\":0.554135},{\\\"timestamp\\\":1481856780,\\\"value\\\":0.428816},{\\\"timestamp\\\":1481856840,\\\"value\\\":1.151386},{\\\"timestamp\\\":1481856900,\\\"value\\\":0.556269},{\\\"timestamp\\\":1481856960,\\\"value\\\":0.469684},{\\\"timestamp\\\":1481857020,\\\"value\\\":0.298380},{\\\"timestamp\\\":1481857080,\\\"value\\\":0.903226},{\\\"timestamp\\\":1481857140,\\\"value\\\":0.426076},{\\\"timestamp\\\":1481857200,\\\"value\\\":0.771208},{\\\"timestamp\\\":1481857260,\\\"value\\\":1.071582},{\\\"timestamp\\\":1481857320,\\\"value\\\":1.278772},{\\\"timestamp\\\":1481857380,\\\"value\\\":0.642674},{\\\"timestamp\\\":1481857440,\\\"value\\\":0.212044},{\\\"timestamp\\\":1481857500,\\\"value\\\":0.686106},{\\\"timestamp\\\":1481857560,\\\"value\\\":0.425713},{\\\"timestamp\\\":1481857620,\\\"value\\\":0.810235},{\\\"timestamp\\\":1481857680,\\\"value\\\":0.765632},{\\\"timestamp\\\":1481857740,\\\"value\\\":0.380389},{\\\"timestamp\\\":1481857800,\\\"value\\\":0.296988},{\\\"timestamp\\\":1481857860,\\\"value\\\":0.855432},{\\\"timestamp\\\":1481857920,\\\"value\\\":0.470286},{\\\"timestamp\\\":1481857980,\\\"value\\\":1.248923},{\\\"timestamp\\\":1481858040,\\\"value\\\":1.631602},{\\\"timestamp\\\":1481858100,\\\"value\\\":1.531263},{\\\"timestamp\\\":1481858160,\\\"value\\\":0.599829}]},{\\\"endpoint\\\":\\\"docker-b\\\",\\\"counter\\\":\\\"cpu.idle\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"Values\\\":[{\\\"timestamp\\\":1481854620,\\\"value\\\":93.811775},{\\\"timestamp\\\":1481854680,\\\"value\\\":94.150538},{\\\"timestamp\\\":1481854740,\\\"value\\\":94.991438},{\\\"timestamp\\\":1481854800,\\\"value\\\":93.287435},{\\\"timestamp\\\":1481854860,\\\"value\\\":96.642584},{\\\"timestamp\\\":1481854920,\\\"value\\\":98.207426},{\\\"timestamp\\\":1481854980,\\\"value\\\":94.801875},{\\\"timestamp\\\":1481855040,\\\"value\\\":97.827939},{\\\"timestamp\\\":1481855100,\\\"value\\\":94.439692},{\\\"timestamp\\\":1481855160,\\\"value\\\":98.292787},{\\\"timestamp\\\":1481855220,\\\"value\\\":95.027624},{\\\"timestamp\\\":1481855280,\\\"value\\\":98.218074},{\\\"timestamp\\\":1481855340,\\\"value\\\":97.402044},{\\\"timestamp\\\":1481855400,\\\"value\\\":94.368601},{\\\"timestamp\\\":1481855460,\\\"value\\\":94.772631},{\\\"timestamp\\\":1481855520,\\\"value\\\":93.992331},{\\\"timestamp\\\":1481855580,\\\"value\\\":94.939446},{\\\"timestamp\\\":1481855640,\\\"value\\\":97.780623},{\\\"timestamp\\\":1481855700,\\\"value\\\":97.860505},{\\\"timestamp\\\":1481855760,\\\"value\\\":92.765411},{\\\"timestamp\\\":1481855820,\\\"value\\\":98.029979},{\\\"timestamp\\\":1481855880,\\\"value\\\":94.523502},{\\\"timestamp\\\":1481855940,\\\"value\\\":94.102564},{\\\"timestamp\\\":1481856000,\\\"value\\\":94.965870},{\\\"timestamp\\\":1481856060,\\\"value\\\":94.382979},{\\\"timestamp\\\":1481856120,\\\"value\\\":93.336181},{\\\"timestamp\\\":1481856180,\\\"value\\\":97.988875},{\\\"timestamp\\\":1481856240,\\\"value\\\":94.401709},{\\\"timestamp\\\":1481856300,\\\"value\\\":94.619983},{\\\"timestamp\\\":1481856360,\\\"value\\\":94.916702},{\\\"timestamp\\\":1481856420,\\\"value\\\":94.089733},{\\\"timestamp\\\":1481856480,\\\"value\\\":94.475375},{\\\"timestamp\\\":1481856540,\\\"value\\\":93.576017},{\\\"timestamp\\\":1481856600,\\\"value\\\":94.010195},{\\\"timestamp\\\":1481856660,\\\"value\\\":94.137783},{\\\"timestamp\\\":1481856720,\\\"value\\\":95.264505},{\\\"timestamp\\\":1481856780,\\\"value\\\":96.879008},{\\\"timestamp\\\":1481856840,\\\"value\\\":96.387590},{\\\"timestamp\\\":1481856900,\\\"value\\\":93.830334},{\\\"timestamp\\\":1481856960,\\\"value\\\":96.282051},{\\\"timestamp\\\":1481857020,\\\"value\\\":94.173093},{\\\"timestamp\\\":1481857080,\\\"value\\\":95.382642},{\\\"timestamp\\\":1481857140,\\\"value\\\":94.107452},{\\\"timestamp\\\":1481857200,\\\"value\\\":93.611584},{\\\"timestamp\\\":1481857260,\\\"value\\\":97.053800},{\\\"timestamp\\\":1481857320,\\\"value\\\":94.404101},{\\\"timestamp\\\":1481857380,\\\"value\\\":94.449189},{\\\"timestamp\\\":1481857440,\\\"value\\\":98.286938},{\\\"timestamp\\\":1481857500,\\\"value\\\":93.720632},{\\\"timestamp\\\":1481857560,\\\"value\\\":93.669803},{\\\"timestamp\\\":1481857620,\\\"value\\\":93.865294},{\\\"timestamp\\\":1481857680,\\\"value\\\":94.498934},{\\\"timestamp\\\":1481857740,\\\"value\\\":94.610778},{\\\"timestamp\\\":1481857800,\\\"value\\\":93.929029},{\\\"timestamp\\\":1481857860,\\\"value\\\":97.827939},{\\\"timestamp\\\":1481857920,\\\"value\\\":97.768240},{\\\"timestamp\\\":1481857980,\\\"value\\\":91.079014},{\\\"timestamp\\\":1481858040,\\\"value\\\":97.854998},{\\\"timestamp\\\":1481858100,\\\"value\\\":93.399482},{\\\"timestamp\\\":1481858160,\\\"value\\\":94.014536}]},{\\\"endpoint\\\":\\\"docker-b\\\",\\\"counter\\\":\\\"cpu.iowait\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"Values\\\":[{\\\"timestamp\\\":1481854620,\\\"value\\\":0.171895},{\\\"timestamp\\\":1481854680,\\\"value\\\":0.645161},{\\\"timestamp\\\":1481854740,\\\"value\\\":0.470890},{\\\"timestamp\\\":1481854800,\\\"value\\\":0.731497},{\\\"timestamp\\\":1481854860,\\\"value\\\":0.594985},{\\\"timestamp\\\":1481854920,\\\"value\\\":0.256082},{\\\"timestamp\\\":1481854980,\\\"value\\\":0.340861},{\\\"timestamp\\\":1481855040,\\\"value\\\":0.255537},{\\\"timestamp\\\":1481855100,\\\"value\\\":0.684346},{\\\"timestamp\\\":1481855160,\\\"value\\\":0.384123},{\\\"timestamp\\\":1481855220,\\\"value\\\":0.084998},{\\\"timestamp\\\":1481855280,\\\"value\\\":0.466695},{\\\"timestamp\\\":1481855340,\\\"value\\\":1.192504},{\\\"timestamp\\\":1481855400,\\\"value\\\":0.511945},{\\\"timestamp\\\":1481855460,\\\"value\\\":0.594985},{\\\"timestamp\\\":1481855520,\\\"value\\\":0.383468},{\\\"timestamp\\\":1481855580,\\\"value\\\":1.038062},{\\\"timestamp\\\":1481855640,\\\"value\\\":0.981647},{\\\"timestamp\\\":1481855700,\\\"value\\\":0.599059},{\\\"timestamp\\\":1481855760,\\\"value\\\":0.770548},{\\\"timestamp\\\":1481855820,\\\"value\\\":0.428266},{\\\"timestamp\\\":1481855880,\\\"value\\\":0.301854},{\\\"timestamp\\\":1481855940,\\\"value\\\":0.598291},{\\\"timestamp\\\":1481856000,\\\"value\\\":0.853242},{\\\"timestamp\\\":1481856060,\\\"value\\\":0.723404},{\\\"timestamp\\\":1481856120,\\\"value\\\":1.025203},{\\\"timestamp\\\":1481856180,\\\"value\\\":0.470689},{\\\"timestamp\\\":1481856240,\\\"value\\\":0.213675},{\\\"timestamp\\\":1481856300,\\\"value\\\":0.768574},{\\\"timestamp\\\":1481856360,\\\"value\\\":0.256301},{\\\"timestamp\\\":1481856420,\\\"value\\\":0.388266},{\\\"timestamp\\\":1481856480,\\\"value\\\":0.342612},{\\\"timestamp\\\":1481856540,\\\"value\\\":0.813704},{\\\"timestamp\\\":1481856600,\\\"value\\\":0.594732},{\\\"timestamp\\\":1481856660,\\\"value\\\":0.684638},{\\\"timestamp\\\":1481856720,\\\"value\\\":1.535836},{\\\"timestamp\\\":1481856780,\\\"value\\\":0.256520},{\\\"timestamp\\\":1481856840,\\\"value\\\":0.382490},{\\\"timestamp\\\":1481856900,\\\"value\\\":1.028278},{\\\"timestamp\\\":1481856960,\\\"value\\\":1.025641},{\\\"timestamp\\\":1481857020,\\\"value\\\":0.642674},{\\\"timestamp\\\":1481857080,\\\"value\\\":0.726806},{\\\"timestamp\\\":1481857140,\\\"value\\\":0.649913},{\\\"timestamp\\\":1481857200,\\\"value\\\":0.809199},{\\\"timestamp\\\":1481857260,\\\"value\\\":0.256191},{\\\"timestamp\\\":1481857320,\\\"value\\\":0.512601},{\\\"timestamp\\\":1481857380,\\\"value\\\":0.597780},{\\\"timestamp\\\":1481857440,\\\"value\\\":0.342612},{\\\"timestamp\\\":1481857500,\\\"value\\\":1.196070},{\\\"timestamp\\\":1481857560,\\\"value\\\":0.983747},{\\\"timestamp\\\":1481857620,\\\"value\\\":0.900901},{\\\"timestamp\\\":1481857680,\\\"value\\\":0.639659},{\\\"timestamp\\\":1481857740,\\\"value\\\":0.641574},{\\\"timestamp\\\":1481857800,\\\"value\\\":0.598546},{\\\"timestamp\\\":1481857860,\\\"value\\\":0.425894},{\\\"timestamp\\\":1481857920,\\\"value\\\":0.729614},{\\\"timestamp\\\":1481857980,\\\"value\\\":0.339847},{\\\"timestamp\\\":1481858040,\\\"value\\\":0.686401},{\\\"timestamp\\\":1481858100,\\\"value\\\":0.560828},{\\\"timestamp\\\":1481858160,\\\"value\\\":0.513040}]},{\\\"endpoint\\\":\\\"docker-c\\\",\\\"counter\\\":\\\"cpu.idle\\\",\\\"dstype\\\":\\\"\\\",\\\"step\\\":0,\\\"Values\\\":[]},{\\\"endpoint\\\":\\\"docker-c\\\",\\\"counter\\\":\\\"cpu.iowait\\\",\\\"dstype\\\":\\\"\\\",\\\"step\\\":0,\\\"Values\\\":[]}]\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>\n"
  },
  {
    "path": "docs/doc/graph.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/graph/endpoint\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/graph/endpoint\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Cookie\": \" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"error\\\":\\\"q is missing\\\"}\",\n          \"ResponseCode\": 400\n        },\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/graph/endpoint\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"\",\n          \"ResponseCode\": 401\n        },\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/graph/endpoint\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Cookie\": \" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"q\": \"a.+\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"endpoint\\\":\\\"docker-agent\\\",\\\"id\\\":7},{\\\"endpoint\\\":\\\"docker-task\\\",\\\"id\\\":6},{\\\"endpoint\\\":\\\"graph\\\",\\\"id\\\":3},{\\\"endpoint\\\":\\\"nodata\\\",\\\"id\\\":920},{\\\"endpoint\\\":\\\"task\\\",\\\"id\\\":5}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/graph/endpoint\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"limit\": \"10\",\n            \"q\": \".+\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"endpoint\\\":\\\"docker-a\\\",\\\"id\\\":244525914},{\\\"endpoint\\\":\\\"docker-b\\\",\\\"id\\\":12675145},{\\\"endpoint\\\":\\\"docker-c\\\",\\\"id\\\":12683936},{\\\"endpoint\\\":\\\"docker-d\\\",\\\"id\\\":12681439},{\\\"endpoint\\\":\\\"docker-f\\\",\\\"id\\\":12676363},{\\\"endpoint\\\":\\\"docker-g\\\",\\\"id\\\":12681715},{\\\"endpoint\\\":\\\"docker-h\\\",\\\"id\\\":12678421},{\\\"endpoint\\\":\\\"docker-i\\\",\\\"id\\\":12676879},{\\\"endpoint\\\":\\\"docker-j\\\",\\\"id\\\":12675447},{\\\"endpoint\\\":\\\"docker-k\\\",\\\"id\\\":12679349}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/graph/endpoint_counter\",\n      \"Calls\": [\n        {\n          \"Id\": 3,\n          \"CurrentPath\": \"/api/v1/graph/endpoint_counter\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Cookie\": \" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"error\\\":\\\"eid is missing\\\"}\",\n          \"ResponseCode\": 400\n        },\n        {\n          \"Id\": 4,\n          \"CurrentPath\": \"/api/v1/graph/endpoint_counter\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Cookie\": \" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"eid\": \"6,7\",\n            \"metricQuery\": \"disk.+\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[\\\"disk.io.avgqu-sz/device=sda\\\",\\\"disk.io.ios_in_progress/device=sda\\\",\\\"disk.io.msec_read/device=sda\\\",\\\"disk.io.read_requests/device=sda\\\",\\\"disk.io.read_sectors/device=sda\\\",\\\"disk.io.write_bytes/device=sda\\\",\\\"disk.io.write_merged/device=sda\\\",\\\"disk.io.msec_write/device=sda\\\",\\\"disk.io.read_merged/device=sda\\\",\\\"disk.io.svctm/device=sda\\\",\\\"disk.io.util/device=sda\\\",\\\"disk.io.avgrq_sz/device=sda\\\",\\\"disk.io.msec_weighted_total/device=sda\\\",\\\"disk.io.await/device=sda\\\",\\\"disk.io.msec_total/device=sda\\\",\\\"disk.io.read_bytes/device=sda\\\",\\\"disk.io.write_requests/device=sda\\\",\\\"disk.io.write_sectors/device=sda\\\"]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/graph/endpoint_counter\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"eid\": \"244525914,12675145,12683936,12681439,12676363,12681715,12678421,12676879,12675447,12679349\",\n            \"limit\": \"3\",\n            \"metricQuery\": \"disk.+\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[\\\"disk.io.write_sectors/device=sdh\\\",\\\"disk.device.size/device=sdm\\\",\\\"disk.io.ios_in_progress/device=sdj\\\"]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/graph/history\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/graph/history\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"step\\\":60,\\\"start_time\\\":1481854596,\\\"hostnames\\\":[\\\"docker-a\\\",\\\"docker-b\\\",\\\"docker-c\\\"],\\\"end_time\\\":1481858193,\\\"counters\\\":[\\\"cpu.idle\\\",\\\"cpu.iowait\\\"],\\\"consol_fun\\\":\\\"AVERAGE\\\"}\",\n          \"ResponseBody\": \"[{\\\"endpoint\\\":\\\"docker-a\\\",\\\"counter\\\":\\\"cpu.idle\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"Values\\\":[{\\\"timestamp\\\":1481854620,\\\"value\\\":98.154506},{\\\"timestamp\\\":1481854680,\\\"value\\\":97.864161},{\\\"timestamp\\\":1481854740,\\\"value\\\":97.521368},{\\\"timestamp\\\":1481854800,\\\"value\\\":97.587247},{\\\"timestamp\\\":1481854860,\\\"value\\\":97.440273},{\\\"timestamp\\\":1481854920,\\\"value\\\":97.914006},{\\\"timestamp\\\":1481854980,\\\"value\\\":97.223409},{\\\"timestamp\\\":1481855040,\\\"value\\\":98.029135},{\\\"timestamp\\\":1481855100,\\\"value\\\":97.614991},{\\\"timestamp\\\":1481855160,\\\"value\\\":97.565143},{\\\"timestamp\\\":1481855220,\\\"value\\\":97.070064},{\\\"timestamp\\\":1481855280,\\\"value\\\":98.726115},{\\\"timestamp\\\":1481855340,\\\"value\\\":98.720137},{\\\"timestamp\\\":1481855400,\\\"value\\\":98.205128},{\\\"timestamp\\\":1481855460,\\\"value\\\":97.700170},{\\\"timestamp\\\":1481855520,\\\"value\\\":97.780623},{\\\"timestamp\\\":1481855580,\\\"value\\\":97.379725},{\\\"timestamp\\\":1481855640,\\\"value\\\":98.034188},{\\\"timestamp\\\":1481855700,\\\"value\\\":98.246364},{\\\"timestamp\\\":1481855760,\\\"value\\\":98.372591},{\\\"timestamp\\\":1481855820,\\\"value\\\":98.152921},{\\\"timestamp\\\":1481855880,\\\"value\\\":97.914006},{\\\"timestamp\\\":1481855940,\\\"value\\\":95.592048},{\\\"timestamp\\\":1481856000,\\\"value\\\":94.115120},{\\\"timestamp\\\":1481856060,\\\"value\\\":97.596567},{\\\"timestamp\\\":1481856120,\\\"value\\\":97.501077},{\\\"timestamp\\\":1481856180,\\\"value\\\":96.374622},{\\\"timestamp\\\":1481856240,\\\"value\\\":89.570815},{\\\"timestamp\\\":1481856300,\\\"value\\\":96.410035},{\\\"timestamp\\\":1481856360,\\\"value\\\":97.567222},{\\\"timestamp\\\":1481856420,\\\"value\\\":97.252040},{\\\"timestamp\\\":1481856480,\\\"value\\\":95.356836},{\\\"timestamp\\\":1481856540,\\\"value\\\":97.330508},{\\\"timestamp\\\":1481856600,\\\"value\\\":96.999571},{\\\"timestamp\\\":1481856660,\\\"value\\\":97.278912},{\\\"timestamp\\\":1481856720,\\\"value\\\":97.229327},{\\\"timestamp\\\":1481856780,\\\"value\\\":97.212693},{\\\"timestamp\\\":1481856840,\\\"value\\\":96.503198},{\\\"timestamp\\\":1481856900,\\\"value\\\":96.790757},{\\\"timestamp\\\":1481856960,\\\"value\\\":98.121264},{\\\"timestamp\\\":1481857020,\\\"value\\\":98.550725},{\\\"timestamp\\\":1481857080,\\\"value\\\":97.548387},{\\\"timestamp\\\":1481857140,\\\"value\\\":98.466127},{\\\"timestamp\\\":1481857200,\\\"value\\\":97.900600},{\\\"timestamp\\\":1481857260,\\\"value\\\":97.985426},{\\\"timestamp\\\":1481857320,\\\"value\\\":97.357204},{\\\"timestamp\\\":1481857380,\\\"value\\\":97.086547},{\\\"timestamp\\\":1481857440,\\\"value\\\":98.770144},{\\\"timestamp\\\":1481857500,\\\"value\\\":97.727273},{\\\"timestamp\\\":1481857560,\\\"value\\\":98.595147},{\\\"timestamp\\\":1481857620,\\\"value\\\":97.867804},{\\\"timestamp\\\":1481857680,\\\"value\\\":98.128456},{\\\"timestamp\\\":1481857740,\\\"value\\\":97.886729},{\\\"timestamp\\\":1481857800,\\\"value\\\":95.969453},{\\\"timestamp\\\":1481857860,\\\"value\\\":97.134303},{\\\"timestamp\\\":1481857920,\\\"value\\\":98.033348},{\\\"timestamp\\\":1481857980,\\\"value\\\":96.511628},{\\\"timestamp\\\":1481858040,\\\"value\\\":96.522112},{\\\"timestamp\\\":1481858100,\\\"value\\\":97.490430},{\\\"timestamp\\\":1481858160,\\\"value\\\":96.958012}]},{\\\"endpoint\\\":\\\"docker-a\\\",\\\"counter\\\":\\\"cpu.iowait\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"Values\\\":[{\\\"timestamp\\\":1481854620,\\\"value\\\":0.815451},{\\\"timestamp\\\":1481854680,\\\"value\\\":0.598035},{\\\"timestamp\\\":1481854740,\\\"value\\\":1.239316},{\\\"timestamp\\\":1481854800,\\\"value\\\":0.775528},{\\\"timestamp\\\":1481854860,\\\"value\\\":0.895904},{\\\"timestamp\\\":1481854920,\\\"value\\\":0.893997},{\\\"timestamp\\\":1481854980,\\\"value\\\":0.811619},{\\\"timestamp\\\":1481855040,\\\"value\\\":0.728363},{\\\"timestamp\\\":1481855100,\\\"value\\\":0.425894},{\\\"timestamp\\\":1481855160,\\\"value\\\":0.768902},{\\\"timestamp\\\":1481855220,\\\"value\\\":1.443737},{\\\"timestamp\\\":1481855280,\\\"value\\\":0.297240},{\\\"timestamp\\\":1481855340,\\\"value\\\":0.213311},{\\\"timestamp\\\":1481855400,\\\"value\\\":0.512821},{\\\"timestamp\\\":1481855460,\\\"value\\\":1.022147},{\\\"timestamp\\\":1481855520,\\\"value\\\":0.810926},{\\\"timestamp\\\":1481855580,\\\"value\\\":0.515464},{\\\"timestamp\\\":1481855640,\\\"value\\\":0.555556},{\\\"timestamp\\\":1481855700,\\\"value\\\":0.470488},{\\\"timestamp\\\":1481855760,\\\"value\\\":0.428266},{\\\"timestamp\\\":1481855820,\\\"value\\\":0.386598},{\\\"timestamp\\\":1481855880,\\\"value\\\":0.638570},{\\\"timestamp\\\":1481855940,\\\"value\\\":0.432152},{\\\"timestamp\\\":1481856000,\\\"value\\\":0.730241},{\\\"timestamp\\\":1481856060,\\\"value\\\":0.643777},{\\\"timestamp\\\":1481856120,\\\"value\\\":0.603188},{\\\"timestamp\\\":1481856180,\\\"value\\\":1.035822},{\\\"timestamp\\\":1481856240,\\\"value\\\":8.927039},{\\\"timestamp\\\":1481856300,\\\"value\\\":0.605536},{\\\"timestamp\\\":1481856360,\\\"value\\\":0.341443},{\\\"timestamp\\\":1481856420,\\\"value\\\":0.343495},{\\\"timestamp\\\":1481856480,\\\"value\\\":0.601892},{\\\"timestamp\\\":1481856540,\\\"value\\\":0.466102},{\\\"timestamp\\\":1481856600,\\\"value\\\":0.557222},{\\\"timestamp\\\":1481856660,\\\"value\\\":0.382653},{\\\"timestamp\\\":1481856720,\\\"value\\\":0.554135},{\\\"timestamp\\\":1481856780,\\\"value\\\":0.428816},{\\\"timestamp\\\":1481856840,\\\"value\\\":1.151386},{\\\"timestamp\\\":1481856900,\\\"value\\\":0.556269},{\\\"timestamp\\\":1481856960,\\\"value\\\":0.469684},{\\\"timestamp\\\":1481857020,\\\"value\\\":0.298380},{\\\"timestamp\\\":1481857080,\\\"value\\\":0.903226},{\\\"timestamp\\\":1481857140,\\\"value\\\":0.426076},{\\\"timestamp\\\":1481857200,\\\"value\\\":0.771208},{\\\"timestamp\\\":1481857260,\\\"value\\\":1.071582},{\\\"timestamp\\\":1481857320,\\\"value\\\":1.278772},{\\\"timestamp\\\":1481857380,\\\"value\\\":0.642674},{\\\"timestamp\\\":1481857440,\\\"value\\\":0.212044},{\\\"timestamp\\\":1481857500,\\\"value\\\":0.686106},{\\\"timestamp\\\":1481857560,\\\"value\\\":0.425713},{\\\"timestamp\\\":1481857620,\\\"value\\\":0.810235},{\\\"timestamp\\\":1481857680,\\\"value\\\":0.765632},{\\\"timestamp\\\":1481857740,\\\"value\\\":0.380389},{\\\"timestamp\\\":1481857800,\\\"value\\\":0.296988},{\\\"timestamp\\\":1481857860,\\\"value\\\":0.855432},{\\\"timestamp\\\":1481857920,\\\"value\\\":0.470286},{\\\"timestamp\\\":1481857980,\\\"value\\\":1.248923},{\\\"timestamp\\\":1481858040,\\\"value\\\":1.631602},{\\\"timestamp\\\":1481858100,\\\"value\\\":1.531263},{\\\"timestamp\\\":1481858160,\\\"value\\\":0.599829}]},{\\\"endpoint\\\":\\\"docker-b\\\",\\\"counter\\\":\\\"cpu.idle\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"Values\\\":[{\\\"timestamp\\\":1481854620,\\\"value\\\":93.811775},{\\\"timestamp\\\":1481854680,\\\"value\\\":94.150538},{\\\"timestamp\\\":1481854740,\\\"value\\\":94.991438},{\\\"timestamp\\\":1481854800,\\\"value\\\":93.287435},{\\\"timestamp\\\":1481854860,\\\"value\\\":96.642584},{\\\"timestamp\\\":1481854920,\\\"value\\\":98.207426},{\\\"timestamp\\\":1481854980,\\\"value\\\":94.801875},{\\\"timestamp\\\":1481855040,\\\"value\\\":97.827939},{\\\"timestamp\\\":1481855100,\\\"value\\\":94.439692},{\\\"timestamp\\\":1481855160,\\\"value\\\":98.292787},{\\\"timestamp\\\":1481855220,\\\"value\\\":95.027624},{\\\"timestamp\\\":1481855280,\\\"value\\\":98.218074},{\\\"timestamp\\\":1481855340,\\\"value\\\":97.402044},{\\\"timestamp\\\":1481855400,\\\"value\\\":94.368601},{\\\"timestamp\\\":1481855460,\\\"value\\\":94.772631},{\\\"timestamp\\\":1481855520,\\\"value\\\":93.992331},{\\\"timestamp\\\":1481855580,\\\"value\\\":94.939446},{\\\"timestamp\\\":1481855640,\\\"value\\\":97.780623},{\\\"timestamp\\\":1481855700,\\\"value\\\":97.860505},{\\\"timestamp\\\":1481855760,\\\"value\\\":92.765411},{\\\"timestamp\\\":1481855820,\\\"value\\\":98.029979},{\\\"timestamp\\\":1481855880,\\\"value\\\":94.523502},{\\\"timestamp\\\":1481855940,\\\"value\\\":94.102564},{\\\"timestamp\\\":1481856000,\\\"value\\\":94.965870},{\\\"timestamp\\\":1481856060,\\\"value\\\":94.382979},{\\\"timestamp\\\":1481856120,\\\"value\\\":93.336181},{\\\"timestamp\\\":1481856180,\\\"value\\\":97.988875},{\\\"timestamp\\\":1481856240,\\\"value\\\":94.401709},{\\\"timestamp\\\":1481856300,\\\"value\\\":94.619983},{\\\"timestamp\\\":1481856360,\\\"value\\\":94.916702},{\\\"timestamp\\\":1481856420,\\\"value\\\":94.089733},{\\\"timestamp\\\":1481856480,\\\"value\\\":94.475375},{\\\"timestamp\\\":1481856540,\\\"value\\\":93.576017},{\\\"timestamp\\\":1481856600,\\\"value\\\":94.010195},{\\\"timestamp\\\":1481856660,\\\"value\\\":94.137783},{\\\"timestamp\\\":1481856720,\\\"value\\\":95.264505},{\\\"timestamp\\\":1481856780,\\\"value\\\":96.879008},{\\\"timestamp\\\":1481856840,\\\"value\\\":96.387590},{\\\"timestamp\\\":1481856900,\\\"value\\\":93.830334},{\\\"timestamp\\\":1481856960,\\\"value\\\":96.282051},{\\\"timestamp\\\":1481857020,\\\"value\\\":94.173093},{\\\"timestamp\\\":1481857080,\\\"value\\\":95.382642},{\\\"timestamp\\\":1481857140,\\\"value\\\":94.107452},{\\\"timestamp\\\":1481857200,\\\"value\\\":93.611584},{\\\"timestamp\\\":1481857260,\\\"value\\\":97.053800},{\\\"timestamp\\\":1481857320,\\\"value\\\":94.404101},{\\\"timestamp\\\":1481857380,\\\"value\\\":94.449189},{\\\"timestamp\\\":1481857440,\\\"value\\\":98.286938},{\\\"timestamp\\\":1481857500,\\\"value\\\":93.720632},{\\\"timestamp\\\":1481857560,\\\"value\\\":93.669803},{\\\"timestamp\\\":1481857620,\\\"value\\\":93.865294},{\\\"timestamp\\\":1481857680,\\\"value\\\":94.498934},{\\\"timestamp\\\":1481857740,\\\"value\\\":94.610778},{\\\"timestamp\\\":1481857800,\\\"value\\\":93.929029},{\\\"timestamp\\\":1481857860,\\\"value\\\":97.827939},{\\\"timestamp\\\":1481857920,\\\"value\\\":97.768240},{\\\"timestamp\\\":1481857980,\\\"value\\\":91.079014},{\\\"timestamp\\\":1481858040,\\\"value\\\":97.854998},{\\\"timestamp\\\":1481858100,\\\"value\\\":93.399482},{\\\"timestamp\\\":1481858160,\\\"value\\\":94.014536}]},{\\\"endpoint\\\":\\\"docker-b\\\",\\\"counter\\\":\\\"cpu.iowait\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"Values\\\":[{\\\"timestamp\\\":1481854620,\\\"value\\\":0.171895},{\\\"timestamp\\\":1481854680,\\\"value\\\":0.645161},{\\\"timestamp\\\":1481854740,\\\"value\\\":0.470890},{\\\"timestamp\\\":1481854800,\\\"value\\\":0.731497},{\\\"timestamp\\\":1481854860,\\\"value\\\":0.594985},{\\\"timestamp\\\":1481854920,\\\"value\\\":0.256082},{\\\"timestamp\\\":1481854980,\\\"value\\\":0.340861},{\\\"timestamp\\\":1481855040,\\\"value\\\":0.255537},{\\\"timestamp\\\":1481855100,\\\"value\\\":0.684346},{\\\"timestamp\\\":1481855160,\\\"value\\\":0.384123},{\\\"timestamp\\\":1481855220,\\\"value\\\":0.084998},{\\\"timestamp\\\":1481855280,\\\"value\\\":0.466695},{\\\"timestamp\\\":1481855340,\\\"value\\\":1.192504},{\\\"timestamp\\\":1481855400,\\\"value\\\":0.511945},{\\\"timestamp\\\":1481855460,\\\"value\\\":0.594985},{\\\"timestamp\\\":1481855520,\\\"value\\\":0.383468},{\\\"timestamp\\\":1481855580,\\\"value\\\":1.038062},{\\\"timestamp\\\":1481855640,\\\"value\\\":0.981647},{\\\"timestamp\\\":1481855700,\\\"value\\\":0.599059},{\\\"timestamp\\\":1481855760,\\\"value\\\":0.770548},{\\\"timestamp\\\":1481855820,\\\"value\\\":0.428266},{\\\"timestamp\\\":1481855880,\\\"value\\\":0.301854},{\\\"timestamp\\\":1481855940,\\\"value\\\":0.598291},{\\\"timestamp\\\":1481856000,\\\"value\\\":0.853242},{\\\"timestamp\\\":1481856060,\\\"value\\\":0.723404},{\\\"timestamp\\\":1481856120,\\\"value\\\":1.025203},{\\\"timestamp\\\":1481856180,\\\"value\\\":0.470689},{\\\"timestamp\\\":1481856240,\\\"value\\\":0.213675},{\\\"timestamp\\\":1481856300,\\\"value\\\":0.768574},{\\\"timestamp\\\":1481856360,\\\"value\\\":0.256301},{\\\"timestamp\\\":1481856420,\\\"value\\\":0.388266},{\\\"timestamp\\\":1481856480,\\\"value\\\":0.342612},{\\\"timestamp\\\":1481856540,\\\"value\\\":0.813704},{\\\"timestamp\\\":1481856600,\\\"value\\\":0.594732},{\\\"timestamp\\\":1481856660,\\\"value\\\":0.684638},{\\\"timestamp\\\":1481856720,\\\"value\\\":1.535836},{\\\"timestamp\\\":1481856780,\\\"value\\\":0.256520},{\\\"timestamp\\\":1481856840,\\\"value\\\":0.382490},{\\\"timestamp\\\":1481856900,\\\"value\\\":1.028278},{\\\"timestamp\\\":1481856960,\\\"value\\\":1.025641},{\\\"timestamp\\\":1481857020,\\\"value\\\":0.642674},{\\\"timestamp\\\":1481857080,\\\"value\\\":0.726806},{\\\"timestamp\\\":1481857140,\\\"value\\\":0.649913},{\\\"timestamp\\\":1481857200,\\\"value\\\":0.809199},{\\\"timestamp\\\":1481857260,\\\"value\\\":0.256191},{\\\"timestamp\\\":1481857320,\\\"value\\\":0.512601},{\\\"timestamp\\\":1481857380,\\\"value\\\":0.597780},{\\\"timestamp\\\":1481857440,\\\"value\\\":0.342612},{\\\"timestamp\\\":1481857500,\\\"value\\\":1.196070},{\\\"timestamp\\\":1481857560,\\\"value\\\":0.983747},{\\\"timestamp\\\":1481857620,\\\"value\\\":0.900901},{\\\"timestamp\\\":1481857680,\\\"value\\\":0.639659},{\\\"timestamp\\\":1481857740,\\\"value\\\":0.641574},{\\\"timestamp\\\":1481857800,\\\"value\\\":0.598546},{\\\"timestamp\\\":1481857860,\\\"value\\\":0.425894},{\\\"timestamp\\\":1481857920,\\\"value\\\":0.729614},{\\\"timestamp\\\":1481857980,\\\"value\\\":0.339847},{\\\"timestamp\\\":1481858040,\\\"value\\\":0.686401},{\\\"timestamp\\\":1481858100,\\\"value\\\":0.560828},{\\\"timestamp\\\":1481858160,\\\"value\\\":0.513040}]},{\\\"endpoint\\\":\\\"docker-c\\\",\\\"counter\\\":\\\"cpu.idle\\\",\\\"dstype\\\":\\\"\\\",\\\"step\\\":0,\\\"Values\\\":[]},{\\\"endpoint\\\":\\\"docker-c\\\",\\\"counter\\\":\\\"cpu.iowait\\\",\\\"dstype\\\":\\\"\\\",\\\"step\\\":0,\\\"Values\\\":[]}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/host.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n\n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n\n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n\n\n    </div>\n\n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n\n                    <p>Production : <strong>/api/v1</strong></p>\n\n                    <p>Staging : <strong>/api/v1</strong></p>\n\n              </div>\n            </div>\n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n\n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/host/1647/template</a></li>\n\n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/host/1647/hostgroup</a></li>\n\n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n\n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">[{&#34;id&#34;:125,&#34;tpl_name&#34;:&#34;tplA&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:99,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:142,&#34;tpl_name&#34;:&#34;tplB&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:111,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:180,&#34;tpl_name&#34;:&#34;tplC&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:142,&#34;create_user&#34;:&#34;root&#34;}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":125,\\\"tpl_name\\\":\\\"tplA\\\",\\\"parent_id\\\":0,\\\"action_id\\\":99,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":142,\\\"tpl_name\\\":\\\"tplB\\\",\\\"parent_id\\\":0,\\\"action_id\\\":111,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":180,\\\"tpl_name\\\":\\\"tplC\\\",\\\"parent_id\\\":0,\\\"action_id\\\":142,\\\"create_user\\\":\\\"root\\\"}]\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">[{&#34;id&#34;:78,&#34;grp_name&#34;:&#34;tplB&#34;,&#34;create_user&#34;:&#34;userA&#34;},{&#34;id&#34;:145,&#34;grp_name&#34;:&#34;Owl_Default_Group&#34;,&#34;create_user&#34;:&#34;userA&#34;}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":78,\\\"grp_name\\\":\\\"tplB\\\",\\\"create_user\\\":\\\"userA\\\"},{\\\"id\\\":145,\\\"grp_name\\\":\\\"Owl_Default_Group\\\",\\\"create_user\\\":\\\"userA\\\"}]\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>\n"
  },
  {
    "path": "docs/doc/host.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/host/1647/template\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/host/1647/template\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":125,\\\"tpl_name\\\":\\\"tplA\\\",\\\"parent_id\\\":0,\\\"action_id\\\":99,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":142,\\\"tpl_name\\\":\\\"tplB\\\",\\\"parent_id\\\":0,\\\"action_id\\\":111,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":180,\\\"tpl_name\\\":\\\"tplC\\\",\\\"parent_id\\\":0,\\\"action_id\\\":142,\\\"create_user\\\":\\\"root\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/host/1647/hostgroup\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/host/1647/hostgroup\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":78,\\\"grp_name\\\":\\\"tplB\\\",\\\"create_user\\\":\\\"userA\\\"},{\\\"id\\\":145,\\\"grp_name\\\":\\\"Owl_Default_Group\\\",\\\"create_user\\\":\\\"userA\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/hostgroup.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n\n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n\n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n\n\n    </div>\n\n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n\n                    <p>Production : <strong>/api/v1</strong></p>\n\n                    <p>Staging : <strong>/api/v1</strong></p>\n\n              </div>\n            </div>\n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n\n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/hostgroup</a></li>\n\n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/hostgroup/host</a></li>\n\n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/hostgroup/host</a></li>\n\n                <li role=\"presentation\"><a href=\"#3top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/hostgroup/343</a></li>\n\n                <li role=\"presentation\"><a href=\"#4top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/hostgroup</a></li>\n\n                <li role=\"presentation\"><a href=\"#5top\" role=\"tab\" data-toggle=\"tab\">DELETE : /api/v1/hostgroup/343</a></li>\n\n                <li role=\"presentation\"><a href=\"#6top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/hostgroup/3/template</a></li>\n\n                <li role=\"presentation\"><a href=\"#7top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/hostgroup/template</a></li>\n\n                <li role=\"presentation\"><a href=\"#8top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/hostgroup/template</a></li>\n\n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n\n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-0\" class=\"prettyprint\">{&#34;name&#34;:&#34;testhostgroup&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"name\\\":\\\"testhostgroup\\\"}\");\n                            document.getElementById('request-body0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">{&#34;id&#34;:343,&#34;grp_name&#34;:&#34;testhostgroup&#34;,&#34;create_user&#34;:&#34;root&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":343,\\\"grp_name\\\":\\\"testhostgroup\\\",\\\"create_user\\\":\\\"root\\\"}\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-1-0\" class=\"prettyprint\">{&#34;hosts&#34;:[&#34;testhostgroup&#34;,&#34;agent_test&#34;],&#34;hostgroup_id&#34;:342}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"hosts\\\":[\\\"testhostgroup\\\",\\\"agent_test\\\"],\\\"hostgroup_id\\\":342}\");\n                            document.getElementById('request-body1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">417</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">{&#34;error&#34;:&#34;record not found&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"record not found\\\"}\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-1-1\" class=\"prettyprint\">{&#34;hosts&#34;:[&#34;testhostgroup&#34;,&#34;agent_test&#34;],&#34;hostgroup_id&#34;:343}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"hosts\\\":[\\\"testhostgroup\\\",\\\"agent_test\\\"],\\\"hostgroup_id\\\":343}\");\n                            document.getElementById('request-body1-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-1\">{&#34;message&#34;:&#34;[9312 9313] bind to hostgroup: 343&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"[9312 9313] bind to hostgroup: 343\\\"}\");\n                            document.getElementById('response-body-1-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-0\" class=\"prettyprint\">{&#34;hostgroup_id&#34;:343,&#34;host_id&#34;:9312}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"hostgroup_id\\\":343,\\\"host_id\\\":9312}\");\n                            document.getElementById('request-body2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">{&#34;message&#34;:&#34;unbind host:9312 of hostgroup: 343&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"unbind host:9312 of hostgroup: 343\\\"}\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"3top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-3-0\">{&#34;hostgroup&#34;:{&#34;id&#34;:343,&#34;grp_name&#34;:&#34;testhostgroup&#34;,&#34;create_user&#34;:&#34;root&#34;},&#34;hosts&#34;:[{&#34;id&#34;:9313,&#34;hostname&#34;:&#34;agent_test&#34;,&#34;ip&#34;:&#34;&#34;,&#34;agent_version&#34;:&#34;&#34;,&#34;plugin_version&#34;:&#34;&#34;,&#34;maintain_begin&#34;:0,&#34;maintain_end&#34;:0}]}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"hostgroup\\\":{\\\"id\\\":343,\\\"grp_name\\\":\\\"testhostgroup\\\",\\\"create_user\\\":\\\"root\\\"},\\\"hosts\\\":[{\\\"id\\\":9313,\\\"hostname\\\":\\\"agent_test\\\",\\\"ip\\\":\\\"\\\",\\\"agent_version\\\":\\\"\\\",\\\"plugin_version\\\":\\\"\\\",\\\"maintain_begin\\\":0,\\\"maintain_end\\\":0}]}\");\n                            document.getElementById('response-body-3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"4top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-0\">[{&#34;id&#34;:3,&#34;grp_name&#34;:&#34;hostnameA&#34;,&#34;create_user&#34;:&#34;UserA&#34;},{&#34;id&#34;:5,&#34;grp_name&#34;:&#34;TAI&#34;,&#34;create_user&#34;:&#34;UserB&#34;},{&#34;id&#34;:8,&#34;grp_name&#34;:&#34;ForTestHostG&#34;,&#34;create_user&#34;:&#34;root&#34;}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":3,\\\"grp_name\\\":\\\"hostnameA\\\",\\\"create_user\\\":\\\"UserA\\\"},{\\\"id\\\":5,\\\"grp_name\\\":\\\"TAI\\\",\\\"create_user\\\":\\\"UserB\\\"},{\\\"id\\\":8,\\\"grp_name\\\":\\\"ForTestHostG\\\",\\\"create_user\\\":\\\"root\\\"}]\");\n                            document.getElementById('response-body-4-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>limit</td>\n                        <td> 10</td>\n                    </tr>\n\n                    <tr>\n                        <td>page</td>\n                        <td> 1</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-1\">[{&#34;id&#34;:3,&#34;grp_name&#34;:&#34;docker-A&#34;,&#34;create_user&#34;:&#34;user-A&#34;},{&#34;id&#34;:5,&#34;grp_name&#34;:&#34;docker-T&#34;,&#34;create_user&#34;:&#34;cheminlin&#34;},{&#34;id&#34;:8,&#34;grp_name&#34;:&#34;docker-F&#34;,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:9,&#34;grp_name&#34;:&#34;docker-B&#34;,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:11,&#34;grp_name&#34;:&#34;docker-D&#34;,&#34;create_user&#34;:&#34;user-C&#34;},{&#34;id&#34;:12,&#34;grp_name&#34;:&#34;docker-E&#34;,&#34;create_user&#34;:&#34;user-C&#34;},{&#34;id&#34;:14,&#34;grp_name&#34;:&#34;docker-G&#34;,&#34;create_user&#34;:&#34;user-C&#34;},{&#34;id&#34;:15,&#34;grp_name&#34;:&#34;docker-G2&#34;,&#34;create_user&#34;:&#34;user-C&#34;},{&#34;id&#34;:16,&#34;grp_name&#34;:&#34;docker-H&#34;,&#34;create_user&#34;:&#34;user-C&#34;},{&#34;id&#34;:17,&#34;grp_name&#34;:&#34;tools&#34;,&#34;create_user&#34;:&#34;user-C&#34;}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":3,\\\"grp_name\\\":\\\"docker-A\\\",\\\"create_user\\\":\\\"user-A\\\"},{\\\"id\\\":5,\\\"grp_name\\\":\\\"docker-T\\\",\\\"create_user\\\":\\\"cheminlin\\\"},{\\\"id\\\":8,\\\"grp_name\\\":\\\"docker-F\\\",\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":9,\\\"grp_name\\\":\\\"docker-B\\\",\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":11,\\\"grp_name\\\":\\\"docker-D\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":12,\\\"grp_name\\\":\\\"docker-E\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":14,\\\"grp_name\\\":\\\"docker-G\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":15,\\\"grp_name\\\":\\\"docker-G2\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":16,\\\"grp_name\\\":\\\"docker-H\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":17,\\\"grp_name\\\":\\\"tools\\\",\\\"create_user\\\":\\\"user-C\\\"}]\");\n                            document.getElementById('response-body-4-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"5top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-5-0\">{&#34;message&#34;:&#34;hostgroup:343 has been deleted&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"hostgroup:343 has been deleted\\\"}\");\n                            document.getElementById('response-body-5-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"6top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-6-0\">{&#34;hostgroup&#34;:{&#34;id&#34;:3,&#34;grp_name&#34;:&#34;hostgroupA&#34;,&#34;create_user&#34;:&#34;root&#34;},&#34;templates&#34;:[{&#34;id&#34;:5,&#34;tpl_name&#34;:&#34;TplA&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:12,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:91,&#34;tpl_name&#34;:&#34;TplB&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:59,&#34;create_user&#34;:&#34;userA&#34;},{&#34;id&#34;:94,&#34;tpl_name&#34;:&#34;TplB&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:62,&#34;create_user&#34;:&#34;userA&#34;},{&#34;id&#34;:103,&#34;tpl_name&#34;:&#34;TplC&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:74,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:104,&#34;tpl_name&#34;:&#34;TplD&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:75,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:105,&#34;tpl_name&#34;:&#34;TplE&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:76,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:116,&#34;tpl_name&#34;:&#34;TplG&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:87,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:125,&#34;tpl_name&#34;:&#34;TplH&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:99,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:126,&#34;tpl_name&#34;:&#34;http&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:100,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:127,&#34;tpl_name&#34;:&#34;TplJ&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:101,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:194,&#34;tpl_name&#34;:&#34;TplK&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:153,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:208,&#34;tpl_name&#34;:&#34;PT_TEST&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:163,&#34;create_user&#34;:&#34;userO&#34;}]}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"hostgroup\\\":{\\\"id\\\":3,\\\"grp_name\\\":\\\"hostgroupA\\\",\\\"create_user\\\":\\\"root\\\"},\\\"templates\\\":[{\\\"id\\\":5,\\\"tpl_name\\\":\\\"TplA\\\",\\\"parent_id\\\":0,\\\"action_id\\\":12,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":91,\\\"tpl_name\\\":\\\"TplB\\\",\\\"parent_id\\\":0,\\\"action_id\\\":59,\\\"create_user\\\":\\\"userA\\\"},{\\\"id\\\":94,\\\"tpl_name\\\":\\\"TplB\\\",\\\"parent_id\\\":0,\\\"action_id\\\":62,\\\"create_user\\\":\\\"userA\\\"},{\\\"id\\\":103,\\\"tpl_name\\\":\\\"TplC\\\",\\\"parent_id\\\":0,\\\"action_id\\\":74,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":104,\\\"tpl_name\\\":\\\"TplD\\\",\\\"parent_id\\\":0,\\\"action_id\\\":75,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":105,\\\"tpl_name\\\":\\\"TplE\\\",\\\"parent_id\\\":0,\\\"action_id\\\":76,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":116,\\\"tpl_name\\\":\\\"TplG\\\",\\\"parent_id\\\":0,\\\"action_id\\\":87,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":125,\\\"tpl_name\\\":\\\"TplH\\\",\\\"parent_id\\\":0,\\\"action_id\\\":99,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":126,\\\"tpl_name\\\":\\\"TplI\\\",\\\"parent_id\\\":0,\\\"action_id\\\":100,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":127,\\\"tpl_name\\\":\\\"TplJ\\\",\\\"parent_id\\\":0,\\\"action_id\\\":101,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":194,\\\"tpl_name\\\":\\\"TplK\\\",\\\"parent_id\\\":0,\\\"action_id\\\":153,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":208,\\\"tpl_name\\\":\\\"PT_TEST\\\",\\\"parent_id\\\":0,\\\"action_id\\\":163,\\\"create_user\\\":\\\"userO\\\"}]}\");\n                            document.getElementById('response-body-6-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"7top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-7-0\" class=\"prettyprint\">{&#34;tpl_id&#34;:5,&#34;grp_id&#34;:3}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tpl_id\\\":5,\\\"grp_id\\\":3}\");\n                            document.getElementById('request-body7-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-7-0\">{&#34;message&#34;:&#34;template: 5 is unbind of HostGroup: 3&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"template: 5 is unbind of HostGroup: 3\\\"}\");\n                            document.getElementById('response-body-7-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"8top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-8-0\" class=\"prettyprint\">{&#34;tpl_id&#34;:5,&#34;grp_id&#34;:3}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tpl_id\\\":5,\\\"grp_id\\\":3}\");\n                            document.getElementById('request-body8-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-8-0\">{&#34;grp_id&#34;:3,&#34;tpl_id&#34;:5,&#34;bind_user&#34;:2}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"grp_id\\\":3,\\\"tpl_id\\\":5,\\\"bind_user\\\":2}\");\n                            document.getElementById('response-body-8-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>\n"
  },
  {
    "path": "docs/doc/hostgroup.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/hostgroup\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/hostgroup\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"name\\\":\\\"testhostgroup\\\"}\",\n          \"ResponseBody\": \"{\\\"id\\\":343,\\\"grp_name\\\":\\\"testhostgroup\\\",\\\"create_user\\\":\\\"root\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/hostgroup/host\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/hostgroup/host\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"hosts\\\":[\\\"testhostgroup\\\",\\\"agent_test\\\"],\\\"hostgroup_id\\\":342}\",\n          \"ResponseBody\": \"{\\\"error\\\":\\\"record not found\\\"}\",\n          \"ResponseCode\": 417\n        },\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/hostgroup/host\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"hosts\\\":[\\\"testhostgroup\\\",\\\"agent_test\\\"],\\\"hostgroup_id\\\":343}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"[9312 9313] bind to hostgroup: 343\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/hostgroup/host\",\n      \"Calls\": [\n        {\n          \"Id\": 3,\n          \"CurrentPath\": \"/api/v1/hostgroup/host\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"hostgroup_id\\\":343,\\\"host_id\\\":9312}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"unbind host:9312 of hostgroup: 343\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/hostgroup/343\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/hostgroup/343\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"hostgroup\\\":{\\\"id\\\":343,\\\"grp_name\\\":\\\"testhostgroup\\\",\\\"create_user\\\":\\\"root\\\"},\\\"hosts\\\":[{\\\"id\\\":9313,\\\"hostname\\\":\\\"agent_test\\\",\\\"ip\\\":\\\"\\\",\\\"agent_version\\\":\\\"\\\",\\\"plugin_version\\\":\\\"\\\",\\\"maintain_begin\\\":0,\\\"maintain_end\\\":0}]}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/hostgroup\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/hostgroup\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":3,\\\"grp_name\\\":\\\"hostnameA\\\",\\\"create_user\\\":\\\"UserA\\\"},{\\\"id\\\":5,\\\"grp_name\\\":\\\"TAI\\\",\\\"create_user\\\":\\\"UserB\\\"},{\\\"id\\\":8,\\\"grp_name\\\":\\\"ForTestHostG\\\",\\\"create_user\\\":\\\"root\\\"}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/hostgroup\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"limit\": \"10\",\n            \"page\": \"1\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":3,\\\"grp_name\\\":\\\"docker-A\\\",\\\"create_user\\\":\\\"user-A\\\"},{\\\"id\\\":5,\\\"grp_name\\\":\\\"docker-T\\\",\\\"create_user\\\":\\\"cheminlin\\\"},{\\\"id\\\":8,\\\"grp_name\\\":\\\"docker-F\\\",\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":9,\\\"grp_name\\\":\\\"docker-B\\\",\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":11,\\\"grp_name\\\":\\\"docker-D\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":12,\\\"grp_name\\\":\\\"docker-E\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":14,\\\"grp_name\\\":\\\"docker-G\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":15,\\\"grp_name\\\":\\\"docker-G2\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":16,\\\"grp_name\\\":\\\"docker-H\\\",\\\"create_user\\\":\\\"user-C\\\"},{\\\"id\\\":17,\\\"grp_name\\\":\\\"tools\\\",\\\"create_user\\\":\\\"user-C\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"DELETE\",\n      \"Path\": \"/api/v1/hostgroup/343\",\n      \"Calls\": [\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/hostgroup/343\",\n          \"MethodType\": \"DELETE\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"hostgroup:343 has been deleted\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/hostgroup/3/template\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/hostgroup/3/template\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"hostgroup\\\":{\\\"id\\\":3,\\\"grp_name\\\":\\\"hostgroupA\\\",\\\"create_user\\\":\\\"root\\\"},\\\"templates\\\":[{\\\"id\\\":5,\\\"tpl_name\\\":\\\"TplA\\\",\\\"parent_id\\\":0,\\\"action_id\\\":12,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":91,\\\"tpl_name\\\":\\\"TplB\\\",\\\"parent_id\\\":0,\\\"action_id\\\":59,\\\"create_user\\\":\\\"userA\\\"},{\\\"id\\\":94,\\\"tpl_name\\\":\\\"TplB\\\",\\\"parent_id\\\":0,\\\"action_id\\\":62,\\\"create_user\\\":\\\"userA\\\"},{\\\"id\\\":103,\\\"tpl_name\\\":\\\"TplC\\\",\\\"parent_id\\\":0,\\\"action_id\\\":74,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":104,\\\"tpl_name\\\":\\\"TplD\\\",\\\"parent_id\\\":0,\\\"action_id\\\":75,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":105,\\\"tpl_name\\\":\\\"TplE\\\",\\\"parent_id\\\":0,\\\"action_id\\\":76,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":116,\\\"tpl_name\\\":\\\"TplG\\\",\\\"parent_id\\\":0,\\\"action_id\\\":87,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":125,\\\"tpl_name\\\":\\\"TplH\\\",\\\"parent_id\\\":0,\\\"action_id\\\":99,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":126,\\\"tpl_name\\\":\\\"TplI\\\",\\\"parent_id\\\":0,\\\"action_id\\\":100,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":127,\\\"tpl_name\\\":\\\"TplJ\\\",\\\"parent_id\\\":0,\\\"action_id\\\":101,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":194,\\\"tpl_name\\\":\\\"TplK\\\",\\\"parent_id\\\":0,\\\"action_id\\\":153,\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":208,\\\"tpl_name\\\":\\\"TplM\\\",\\\"parent_id\\\":0,\\\"action_id\\\":163,\\\"create_user\\\":\\\"userO\\\"}]}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/hostgroup/template\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/hostgroup/template\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tpl_id\\\":5,\\\"grp_id\\\":3}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"template: 5 is unbind of HostGroup: 3\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/hostgroup/template\",\n      \"Calls\": [\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/hostgroup/template\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tpl_id\\\":5,\\\"grp_id\\\":3}\",\n          \"ResponseBody\": \"{\\\"grp_id\\\":3,\\\"tpl_id\\\":5,\\\"bind_user\\\":2}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/nodata.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n    \n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n    \n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n         \n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n        \n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n            \n        \n    </div>\n    \n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n                \n                    <p>Production : <strong>/api/v1</strong></p>\n                \n                    <p>Staging : <strong>/api/v1</strong></p>\n                \n              </div>\n            </div>    \n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n            \n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/nodata</a></li>\n            \n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/nodata/2</a></li>\n            \n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/nodata/</a></li>\n            \n                <li role=\"presentation\"><a href=\"#3top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/nodata/</a></li>\n            \n                <li role=\"presentation\"><a href=\"#4top\" role=\"tab\" data-toggle=\"tab\">DELETE : /api/v1/nodata/4</a></li>\n            \n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n        \n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>limit</td>\n                        <td> 2</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>page</td>\n                        <td> 1</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">[{&#34;id&#34;:2,&#34;name&#34;:&#34;owl_nodate&#34;,&#34;obj&#34;:&#34;docker-agent&#34;,&#34;obj_type&#34;:&#34;host&#34;,&#34;metric&#34;:&#34;test.metric&#34;,&#34;tags&#34;:&#34;&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;mock&#34;:-2,&#34;creator&#34;:&#34;root&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":2,\\\"name\\\":\\\"owl_nodate\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"obj_type\\\":\\\"host\\\",\\\"metric\\\":\\\"test.metric\\\",\\\"tags\\\":\\\"\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"mock\\\":-2,\\\"creator\\\":\\\"root\\\"}]\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">{&#34;id&#34;:2,&#34;name&#34;:&#34;owl_nodate&#34;,&#34;obj&#34;:&#34;docker-agent&#34;,&#34;obj_type&#34;:&#34;host&#34;,&#34;metric&#34;:&#34;test.metric&#34;,&#34;tags&#34;:&#34;&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;mock&#34;:-2,&#34;creator&#34;:&#34;root&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":2,\\\"name\\\":\\\"owl_nodate\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"obj_type\\\":\\\"host\\\",\\\"metric\\\":\\\"test.metric\\\",\\\"tags\\\":\\\"\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"mock\\\":-2,\\\"creator\\\":\\\"root\\\"}\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-0\" class=\"prettyprint\">{&#34;tags&#34;:&#34;&#34;,&#34;step&#34;:60,&#34;obj_type&#34;:&#34;test&#34;,&#34;obj&#34;:&#34;docker-agent&#34;,&#34;name&#34;:&#34;testnodata&#34;,&#34;mock&#34;:-1,&#34;metric&#34;:&#34;test.metric&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"obj_type\\\":\\\"test\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"name\\\":\\\"testnodata\\\",\\\"mock\\\":-1,\\\"metric\\\":\\\"test.metric\\\",\\\"dstype\\\":\\\"GAUGE\\\"}\");\n                            document.getElementById('request-body2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">400</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">{&#34;error&#34;:&#34;obj_type only accpect \\&#34;group, host, other\\&#34;&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"obj_type only accpect \\\\\\\"group, host, other\\\\\\\"\\\"}\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-1\" class=\"prettyprint\">{&#34;tags&#34;:&#34;&#34;,&#34;step&#34;:60,&#34;obj_type&#34;:&#34;host&#34;,&#34;obj&#34;:&#34;docker-agent&#34;,&#34;name&#34;:&#34;testnodata&#34;,&#34;mock&#34;:-1,&#34;metric&#34;:&#34;test.metric&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"obj_type\\\":\\\"host\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"name\\\":\\\"testnodata\\\",\\\"mock\\\":-1,\\\"metric\\\":\\\"test.metric\\\",\\\"dstype\\\":\\\"GAUGE\\\"}\");\n                            document.getElementById('request-body2-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-1\">{&#34;id&#34;:4,&#34;name&#34;:&#34;testnodata&#34;,&#34;obj&#34;:&#34;docker-agent&#34;,&#34;obj_type&#34;:&#34;host&#34;,&#34;metric&#34;:&#34;test.metric&#34;,&#34;tags&#34;:&#34;&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;mock&#34;:-1,&#34;creator&#34;:&#34;root&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":4,\\\"name\\\":\\\"testnodata\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"obj_type\\\":\\\"host\\\",\\\"metric\\\":\\\"test.metric\\\",\\\"tags\\\":\\\"\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"mock\\\":-1,\\\"creator\\\":\\\"root\\\"}\");\n                            document.getElementById('response-body-2-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"3top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-3-0\" class=\"prettyprint\">{&#34;tags&#34;:&#34;&#34;,&#34;step&#34;:60,&#34;obj_type&#34;:&#34;host&#34;,&#34;obj&#34;:&#34;docker-agent&#34;,&#34;mock&#34;:-2,&#34;metric&#34;:&#34;test.metric&#34;,&#34;id&#34;:4,&#34;dstype&#34;:&#34;GAUGE&#34;}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"obj_type\\\":\\\"host\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"mock\\\":-2,\\\"metric\\\":\\\"test.metric\\\",\\\"id\\\":4,\\\"dstype\\\":\\\"GAUGE\\\"}\");\n                            document.getElementById('request-body3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-3-0\">{&#34;id&#34;:0,&#34;name&#34;:&#34;&#34;,&#34;obj&#34;:&#34;docker-agent&#34;,&#34;obj_type&#34;:&#34;host&#34;,&#34;metric&#34;:&#34;test.metric&#34;,&#34;tags&#34;:&#34;&#34;,&#34;dstype&#34;:&#34;GAUGE&#34;,&#34;step&#34;:60,&#34;mock&#34;:-2,&#34;creator&#34;:&#34;&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":0,\\\"name\\\":\\\"\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"obj_type\\\":\\\"host\\\",\\\"metric\\\":\\\"test.metric\\\",\\\"tags\\\":\\\"\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"mock\\\":-2,\\\"creator\\\":\\\"\\\"}\");\n                            document.getElementById('response-body-3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"4top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-0\">{&#34;message&#34;:&#34;mockcfg:4 is deleted&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"mockcfg:4 is deleted\\\"}\");\n                            document.getElementById('response-body-4-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>"
  },
  {
    "path": "docs/doc/nodata.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/nodata\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/nodata\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"limit\": \"2\",\n            \"page\": \"1\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":2,\\\"name\\\":\\\"owl_nodate\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"obj_type\\\":\\\"host\\\",\\\"metric\\\":\\\"test.metric\\\",\\\"tags\\\":\\\"\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"mock\\\":-2,\\\"creator\\\":\\\"root\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/nodata/2\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/nodata/2\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"id\\\":2,\\\"name\\\":\\\"owl_nodate\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"obj_type\\\":\\\"host\\\",\\\"metric\\\":\\\"test.metric\\\",\\\"tags\\\":\\\"\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"mock\\\":-2,\\\"creator\\\":\\\"root\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/nodata/\",\n      \"Calls\": [\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/nodata/\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"obj_type\\\":\\\"test\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"name\\\":\\\"testnodata\\\",\\\"mock\\\":-1,\\\"metric\\\":\\\"test.metric\\\",\\\"dstype\\\":\\\"GAUGE\\\"}\",\n          \"ResponseBody\": \"{\\\"error\\\":\\\"obj_type only accpect \\\\\\\"group, host, other\\\\\\\"\\\"}\",\n          \"ResponseCode\": 400\n        },\n        {\n          \"Id\": 3,\n          \"CurrentPath\": \"/api/v1/nodata/\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"obj_type\\\":\\\"host\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"name\\\":\\\"testnodata\\\",\\\"mock\\\":-1,\\\"metric\\\":\\\"test.metric\\\",\\\"dstype\\\":\\\"GAUGE\\\"}\",\n          \"ResponseBody\": \"{\\\"id\\\":4,\\\"name\\\":\\\"testnodata\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"obj_type\\\":\\\"host\\\",\\\"metric\\\":\\\"test.metric\\\",\\\"tags\\\":\\\"\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"mock\\\":-1,\\\"creator\\\":\\\"root\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/nodata/\",\n      \"Calls\": [\n        {\n          \"Id\": 4,\n          \"CurrentPath\": \"/api/v1/nodata/\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tags\\\":\\\"\\\",\\\"step\\\":60,\\\"obj_type\\\":\\\"host\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"mock\\\":-2,\\\"metric\\\":\\\"test.metric\\\",\\\"id\\\":4,\\\"dstype\\\":\\\"GAUGE\\\"}\",\n          \"ResponseBody\": \"{\\\"id\\\":0,\\\"name\\\":\\\"\\\",\\\"obj\\\":\\\"docker-agent\\\",\\\"obj_type\\\":\\\"host\\\",\\\"metric\\\":\\\"test.metric\\\",\\\"tags\\\":\\\"\\\",\\\"dstype\\\":\\\"GAUGE\\\",\\\"step\\\":60,\\\"mock\\\":-2,\\\"creator\\\":\\\"\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"DELETE\",\n      \"Path\": \"/api/v1/nodata/4\",\n      \"Calls\": [\n        {\n          \"Id\": 5,\n          \"CurrentPath\": \"/api/v1/nodata/4\",\n          \"MethodType\": \"DELETE\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"mockcfg:4 is deleted\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/plugin.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n    \n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n    \n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n         \n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n        \n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n            \n        \n    </div>\n    \n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n                \n                    <p>Production : <strong>/api/v1</strong></p>\n                \n                    <p>Staging : <strong>/api/v1</strong></p>\n                \n              </div>\n            </div>    \n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n            \n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/plugin</a></li>\n            \n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/hostgroup/343/plugins</a></li>\n            \n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">DELETE : /api/v1/plugin/1501</a></li>\n            \n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n        \n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-0\" class=\"prettyprint\">{&#34;hostgroup_id&#34;:343,&#34;dir_path&#34;:&#34;testpath&#34;}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"hostgroup_id\\\":343,\\\"dir_path\\\":\\\"testpath\\\"}\");\n                            document.getElementById('request-body0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">{&#34;id&#34;:1501,&#34;grp_id&#34;:343,&#34;dir&#34;:&#34;testpath&#34;,&#34;create_user&#34;:&#34;root&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":1501,\\\"grp_id\\\":343,\\\"dir\\\":\\\"testpath\\\",\\\"create_user\\\":\\\"root\\\"}\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">[{&#34;id&#34;:1499,&#34;grp_id&#34;:343,&#34;dir&#34;:&#34;testpath&#34;,&#34;create_user&#34;:&#34;root&#34;},{&#34;id&#34;:1501,&#34;grp_id&#34;:343,&#34;dir&#34;:&#34;testpath&#34;,&#34;create_user&#34;:&#34;root&#34;}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":1499,\\\"grp_id\\\":343,\\\"dir\\\":\\\"testpath\\\",\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":1501,\\\"grp_id\\\":343,\\\"dir\\\":\\\"testpath\\\",\\\"create_user\\\":\\\"root\\\"}]\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">{&#34;message&#34;:&#34;plugin:1501 is deleted&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"plugin:1501 is deleted\\\"}\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>"
  },
  {
    "path": "docs/doc/plugin.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/plugin\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/plugin\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"hostgroup_id\\\":343,\\\"dir_path\\\":\\\"testpath\\\"}\",\n          \"ResponseBody\": \"{\\\"id\\\":1501,\\\"grp_id\\\":343,\\\"dir\\\":\\\"testpath\\\",\\\"create_user\\\":\\\"root\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/hostgroup/343/plugins\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/hostgroup/343/plugins\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":1499,\\\"grp_id\\\":343,\\\"dir\\\":\\\"testpath\\\",\\\"create_user\\\":\\\"root\\\"},{\\\"id\\\":1501,\\\"grp_id\\\":343,\\\"dir\\\":\\\"testpath\\\",\\\"create_user\\\":\\\"root\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"DELETE\",\n      \"Path\": \"/api/v1/plugin/1501\",\n      \"Calls\": [\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/plugin/1501\",\n          \"MethodType\": \"DELETE\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"plugin:1501 is deleted\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/team.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n    \n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n    \n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n         \n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n        \n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n            \n        \n    </div>\n    \n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n                \n                    <p>Production : <strong>/api/v1</strong></p>\n                \n                    <p>Staging : <strong>/api/v1</strong></p>\n                \n              </div>\n            </div>    \n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n            \n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/team</a></li>\n            \n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/team</a></li>\n            \n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/team</a></li>\n            \n                <li role=\"presentation\"><a href=\"#3top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/team/107</a></li>\n            \n                <li role=\"presentation\"><a href=\"#4top\" role=\"tab\" data-toggle=\"tab\">DELETE : /api/v1/team/107</a></li>\n            \n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n        \n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;dd81ea033c2d11e6a95d0242ac11000c&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-0\" class=\"prettyprint\">{&#34;resume&#34;: &#34;i&#39;m descript&#34;}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" \"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"resume\\\": \\\"i'm descript\\\"}\");\n                            document.getElementById('request-body0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">400</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token,Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">{&#34;error&#34;:&#34;Key: &#39;APICreateTeamInput.Name&#39; Error:Field validation for &#39;Name&#39; failed on the &#39;required&#39; tag&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token,Apitoken\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"Key: 'APICreateTeamInput.Name' Error:Field validation for 'Name' failed on the 'required' tag\\\"}\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;dd81ea033c2d11e6a95d0242ac11000c&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-1\" class=\"prettyprint\">{&#34;team_name&#34;: &#34;ateamname&#34;,&#34;resume&#34;: &#34;i&#39;m descript&#34;, &#34;users&#34;: [1]}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" \"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"team_name\\\": \\\"ateamname\\\",\\\"resume\\\": \\\"i'm descript\\\", \\\"users\\\": [1]}\");\n                            document.getElementById('request-body0-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token,Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-1\">{&#34;message&#34;:&#34;team created! Afftect row: 1, Affect refer: 1&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token,Apitoken\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"team created! Afftect row: 1, Affect refer: 1\\\"}\");\n                            document.getElementById('response-body-0-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;dd81ea033c2d11e6a95d0242ac11000c&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>q</td>\n                        <td> .&#43;</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token,Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">[{&#34;id&#34;:1,&#34;name&#34;:&#34;a&#34;,&#34;resume&#34;:&#34;&#34;,&#34;creator&#34;:1},{&#34;id&#34;:2,&#34;name&#34;:&#34;b&#34;,&#34;resume&#34;:&#34;g&#34;,&#34;creator&#34;:1},{&#34;id&#34;:4,&#34;name&#34;:&#34;testteam&#34;,&#34;resume&#34;:&#34;i&#39;m test&#34;,&#34;creator&#34;:15},{&#34;id&#34;:5,&#34;name&#34;:&#34;atestteam&#34;,&#34;resume&#34;:&#34;i&#39;m test&#34;,&#34;creator&#34;:16},{&#34;id&#34;:107,&#34;name&#34;:&#34;ateamname&#34;,&#34;resume&#34;:&#34;i&#39;m descript&#34;,&#34;creator&#34;:1}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token,Apitoken\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":1,\\\"name\\\":\\\"a\\\",\\\"resume\\\":\\\"\\\",\\\"creator\\\":1},{\\\"id\\\":2,\\\"name\\\":\\\"b\\\",\\\"resume\\\":\\\"g\\\",\\\"creator\\\":1},{\\\"id\\\":4,\\\"name\\\":\\\"testteam\\\",\\\"resume\\\":\\\"i'm test\\\",\\\"creator\\\":15},{\\\"id\\\":5,\\\"name\\\":\\\"atestteam\\\",\\\"resume\\\":\\\"i'm test\\\",\\\"creator\\\":16},{\\\"id\\\":107,\\\"name\\\":\\\"ateamname\\\",\\\"resume\\\":\\\"i'm descript\\\",\\\"creator\\\":1}]\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;dd81ea033c2d11e6a95d0242ac11000c&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>q</td>\n                        <td> ateamname</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token,Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-1\">[{&#34;id&#34;:107,&#34;name&#34;:&#34;ateamname&#34;,&#34;resume&#34;:&#34;i&#39;m descript&#34;,&#34;creator&#34;:1}]</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token,Apitoken\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":107,\\\"name\\\":\\\"ateamname\\\",\\\"resume\\\":\\\"i'm descript\\\",\\\"creator\\\":1}]\");\n                            document.getElementById('response-body-1-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;dd81ea033c2d11e6a95d0242ac11000c&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-0\" class=\"prettyprint\">{&#34;team_id&#34;: 107, &#34;resume&#34;: &#34;i&#39;m descript update&#34;, &#34;users&#34;: [4,5,6,7]}</pre>\n                <script>\n                     \n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" \"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"team_id\\\": 107, \\\"resume\\\": \\\"i'm descript update\\\", \\\"users\\\": [4,5,6,7]}\");\n                            document.getElementById('request-body2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token,Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">{&#34;message&#34;:&#34;team updated!&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token,Apitoken\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"team updated!\\\"}\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"3top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;dd81ea033c2d11e6a95d0242ac11000c&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token,Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-3-0\">{&#34;id&#34;:107,&#34;name&#34;:&#34;ateamname&#34;,&#34;resume&#34;:&#34;i&#39;m descript&#34;,&#34;creator&#34;:1,&#34;users&#34;:[{&#34;id&#34;:4,&#34;name&#34;:&#34;test1&#34;,&#34;cnname&#34;:&#34;翱鶚Test&#34;,&#34;email&#34;:&#34;root123@cepave.com&#34;,&#34;phone&#34;:&#34;99999999999&#34;,&#34;im&#34;:&#34;44955834958&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:5,&#34;name&#34;:&#34;don&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:6,&#34;name&#34;:&#34;masato&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:7,&#34;name&#34;:&#34;cepave1&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0}]}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token,Apitoken\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":107,\\\"name\\\":\\\"ateamname\\\",\\\"resume\\\":\\\"i'm descript\\\",\\\"creator\\\":1,\\\"users\\\":[{\\\"id\\\":4,\\\"name\\\":\\\"test1\\\",\\\"cnname\\\":\\\"翱鶚Test\\\",\\\"email\\\":\\\"root123@cepave.com\\\",\\\"phone\\\":\\\"99999999999\\\",\\\"im\\\":\\\"44955834958\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":5,\\\"name\\\":\\\"don\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":6,\\\"name\\\":\\\"masato\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":7,\\\"name\\\":\\\"cepave1\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0}]}\");\n                            document.getElementById('response-body-3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n        <div id=\"4top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n            \n                \n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;: &#34;root&#34;, &#34;sig&#34;: &#34;dd81ea033c2d11e6a95d0242ac11000c&#34;}</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n                    \n                </table>\n                \n                \n                \n                \n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n                \n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token,Apitoken</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n                    \n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n                    \n                </table>\n                \n                \n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-0\">{&#34;message&#34;:&#34;team 107 is deleted. Affect row: 1 / refer delete: 4&#34;}</pre>\n                <script>\n                     \n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token,Apitoken\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"team 107 is deleted. Affect row: 1 / refer delete: 4\\\"}\");\n                            document.getElementById('response-body-4-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n                             \n                        }\n                    }\n                </script>\n                \n                <hr>\n            \n        </div>\n        \n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>"
  },
  {
    "path": "docs/doc/team.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/team\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/team\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token,Apitoken\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"resume\\\": \\\"i'm descript\\\"}\",\n          \"ResponseBody\": \"{\\\"error\\\":\\\"Key: 'APICreateTeamInput.Name' Error:Field validation for 'Name' failed on the 'required' tag\\\"}\",\n          \"ResponseCode\": 400\n        },\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/team\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token,Apitoken\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"team_name\\\": \\\"ateamname\\\",\\\"resume\\\": \\\"i'm descript\\\", \\\"users\\\": [1]}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"team created! Afftect row: 1, Affect refer: 1\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/team\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/team\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token,Apitoken\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"q\": \".+\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":1,\\\"name\\\":\\\"a\\\",\\\"resume\\\":\\\"\\\",\\\"creator\\\":1},{\\\"id\\\":2,\\\"name\\\":\\\"b\\\",\\\"resume\\\":\\\"g\\\",\\\"creator\\\":1},{\\\"id\\\":4,\\\"name\\\":\\\"testteam\\\",\\\"resume\\\":\\\"i'm test\\\",\\\"creator\\\":15},{\\\"id\\\":5,\\\"name\\\":\\\"atestteam\\\",\\\"resume\\\":\\\"i'm test\\\",\\\"creator\\\":16},{\\\"id\\\":107,\\\"name\\\":\\\"ateamname\\\",\\\"resume\\\":\\\"i'm descript\\\",\\\"creator\\\":1}]\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/team\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token,Apitoken\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"q\": \"ateamname\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":107,\\\"name\\\":\\\"ateamname\\\",\\\"resume\\\":\\\"i'm descript\\\",\\\"creator\\\":1}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/team\",\n      \"Calls\": [\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/team\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token,Apitoken\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"team_id\\\": 107, \\\"resume\\\": \\\"i'm descript update\\\", \\\"users\\\": [4,5,6,7]}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"team updated!\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/team/107\",\n      \"Calls\": [\n        {\n          \"Id\": 4,\n          \"CurrentPath\": \"/api/v1/team/107\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token,Apitoken\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"id\\\":107,\\\"name\\\":\\\"ateamname\\\",\\\"resume\\\":\\\"i'm descript\\\",\\\"creator\\\":1,\\\"users\\\":[{\\\"id\\\":4,\\\"name\\\":\\\"test1\\\",\\\"cnname\\\":\\\"翱鶚Test\\\",\\\"email\\\":\\\"root123@cepave.com\\\",\\\"phone\\\":\\\"99999999999\\\",\\\"im\\\":\\\"44955834958\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":5,\\\"name\\\":\\\"don\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":6,\\\"name\\\":\\\"masato\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":7,\\\"name\\\":\\\"cepave1\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0}]}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"DELETE\",\n      \"Path\": \"/api/v1/team/107\",\n      \"Calls\": [\n        {\n          \"Id\": 6,\n          \"CurrentPath\": \"/api/v1/team/107\",\n          \"MethodType\": \"DELETE\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\": \\\"root\\\", \\\"sig\\\": \\\"dd81ea033c2d11e6a95d0242ac11000c\\\"}\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token,Apitoken\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"team 107 is deleted. Affect row: 1 / refer delete: 4\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/template.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n\n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n\n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n\n\n    </div>\n\n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n\n                    <p>Production : <strong>/api/v1</strong></p>\n\n                    <p>Staging : <strong>/api/v1</strong></p>\n\n              </div>\n            </div>\n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n\n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/template/178</a></li>\n\n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/user/auth_session</a></li>\n\n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/template</a></li>\n\n                <li role=\"presentation\"><a href=\"#3top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/template</a></li>\n\n                <li role=\"presentation\"><a href=\"#4top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/template/action</a></li>\n\n                <li role=\"presentation\"><a href=\"#5top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/template</a></li>\n\n                <li role=\"presentation\"><a href=\"#6top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/template/action</a></li>\n\n                <li role=\"presentation\"><a href=\"#7top\" role=\"tab\" data-toggle=\"tab\">DELETE : /api/v1/template/225</a></li>\n\n                <li role=\"presentation\"><a href=\"#8top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/strategy</a></li>\n\n                <li role=\"presentation\"><a href=\"#9top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/strategy</a></li>\n\n                <li role=\"presentation\"><a href=\"#10top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/strategy/904</a></li>\n\n                <li role=\"presentation\"><a href=\"#11top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/strategy</a></li>\n\n                <li role=\"presentation\"><a href=\"#12top\" role=\"tab\" data-toggle=\"tab\">DELETE : /api/v1/strategy/904</a></li>\n\n                <li role=\"presentation\"><a href=\"#13top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/metric/default_list</a></li>\n\n                <li role=\"presentation\"><a href=\"#14top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/template_simple</a></li>\n\n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n\n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">{\"action\":{\"id\":141,\"uic\":\"admin,mm1\",\"url\":\"\",\"callback\":0,\"before_callback_sms\":0,\"before_callback_mail\":0,\"after_callback_sms\":0,\"after_callback_mail\":0},\"stratges\":[{\"id\":686,\"metric\":\"xxx.check\",\"tags\":\"name=xxx\",\"max_step\":3,\"priority\":2,\"func\":\"all(#2)\",\"op\":\"<\",\"right_value\":\"1\",\"note\":\"xxx服务异常\",\"run_begin\":\"\",\"run_end\":\"\",\"tpl_id\":178},{\"id\":687,\"metric\":\"xxx.sync\",\"tags\":\"\",\"max_step\":3,\"priority\":2,\"func\":\"all(#3)\",\"op\":\"!=\",\"right_value\":\"0\",\"note\":\"XXX同步异常\",\"run_begin\":\"\",\"run_end\":\"\",\"tpl_id\":178},{\"id\":688,\"metric\":\"bbb.check.mq\",\"tags\":\"\",\"max_step\":3,\"priority\":2,\"func\":\"all(#3)\",\"op\":\"==\",\"right_value\":\"1\",\"note\":\"bbb连接MQ异常\",\"run_begin\":\"\",\"run_end\":\"\",\"tpl_id\":178},{\"id\":793,\"metric\":\"aaa.proc.num\",\"tags\":\"\",\"max_step\":3,\"priority\":2,\"func\":\"all(#3)\",\"op\":\"==\",\"right_value\":\"1\",\"note\":\"aaaa 进程大于5\",\"run_begin\":\"\",\"run_end\":\"\",\"tpl_id\":178}],\"template\":{\"id\":178,\"tpl_name\":\"TemplateA\",\"parent_id\":0,\"action_id\":141,\"create_user\":\"root\"}}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"action\\\":{\\\"id\\\":141,\\\"uic\\\":\\\"admin,mm1\\\",\\\"url\\\":\\\"\\\",\\\"callback\\\":0,\\\"before_callback_sms\\\":0,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":0,\\\"after_callback_mail\\\":0},\\\"stratges\\\":[{\\\"id\\\":686,\\\"metric\\\":\\\"xxx.check\\\",\\\"tags\\\":\\\"name=xxx\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#2)\\\",\\\"op\\\":\\\"<\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"xxx服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":178},{\\\"id\\\":687,\\\"metric\\\":\\\"xxx.sync\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"!=\\\",\\\"right_value\\\":\\\"0\\\",\\\"note\\\":\\\"XXX同步异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":178},{\\\"id\\\":688,\\\"metric\\\":\\\"bbb.check.mq\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"bbb连接MQ异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":178},{\\\"id\\\":793,\\\"metric\\\":\\\"aaa.proc.num\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"aaaa 进程大于5\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":178}],\\\"template\\\":{\\\"id\\\":178,\\\"tpl_name\\\":\\\"TemplateA\\\",\\\"parent_id\\\":0,\\\"action_id\\\":141,\\\"create_user\\\":\\\"root\\\"}}\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">{&#34;message&#34;:&#34;session is vaild!&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"session is vaild!\\\"}\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">[{\"id\":1,\"tpl_name\":\"cpu.board\",\"parent_id\":0,\"action_id\":5,\"create_user\":\"usera\"},{\"id\":2,\"tpl_name\":\"traffic checking\",\"parent_id\":0,\"action_id\":6,\"create_user\":\"userb\"},{\"id\":3,\"tpl_name\":\"cputest\",\"parent_id\":0,\"action_id\":7,\"create_user\":\"userc\"},{\"id\":5,\"tpl_name\":\"all metrics base\",\"parent_id\":0,\"action_id\":12,\"create_user\":\"root\"}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":1,\\\"tpl_name\\\":\\\"cpu.board\\\",\\\"parent_id\\\":0,\\\"action_id\\\":5,\\\"create_user\\\":\\\"usera\\\"},{\\\"id\\\":2,\\\"tpl_name\\\":\\\"traffic checking\\\",\\\"parent_id\\\":0,\\\"action_id\\\":6,\\\"create_user\\\":\\\"userb\\\"},{\\\"id\\\":3,\\\"tpl_name\\\":\\\"cputest\\\",\\\"parent_id\\\":0,\\\"action_id\\\":7,\\\"create_user\\\":\\\"userc\\\"},{\\\"id\\\":5,\\\"tpl_name\\\":\\\"all metrics base\\\",\\\"parent_id\\\":0,\\\"action_id\\\":12,\\\"create_user\\\":\\\"root\\\"}]\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"3top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\n</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-3-0\" class=\"prettyprint\">{&#34;parent_id&#34;:0,&#34;name&#34;:&#34;AtmpForTesting&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"parent_id\\\":0,\\\"name\\\":\\\"AtmpForTesting\\\"}\");\n                            document.getElementById('request-body3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-3-0\">{&#34;message&#34;:&#34;template created&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"template created\\\"}\");\n                            document.getElementById('response-body-3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"4top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\n</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-4-0\" class=\"prettyprint\">{&#34;url&#34;:&#34;&#34;,&#34;uic&#34;:&#34;test,tt2&#34;,&#34;tpl_id&#34;:225,&#34;callback&#34;:1,&#34;before_callback_sms&#34;:0,&#34;before_callback_mail&#34;:0,&#34;after_callback_sms&#34;:0,&#34;after_callback_mail&#34;:0}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"url\\\":\\\"\\\",\\\"uic\\\":\\\"test,tt2\\\",\\\"tpl_id\\\":225,\\\"callback\\\":1,\\\"before_callback_sms\\\":0,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":0,\\\"after_callback_mail\\\":0}\");\n                            document.getElementById('request-body4-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-0\">{&#34;message&#34;:&#34;action is created and bind to template: 225&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"action is created and bind to template: 225\\\"}\");\n                            document.getElementById('response-body-4-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"5top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\n</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-5-0\" class=\"prettyprint\">{&#34;tpl_id&#34;:225,&#34;parent_id&#34;:0,&#34;name&#34;:&#34;AtmpForTesting2&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tpl_id\\\":225,\\\"parent_id\\\":0,\\\"name\\\":\\\"AtmpForTesting2\\\"}\");\n                            document.getElementById('request-body5-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-5-0\">{&#34;message&#34;:&#34;template updated&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"template updated\\\"}\");\n                            document.getElementById('response-body-5-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"6top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\n</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-6-0\" class=\"prettyprint\">{&#34;url&#34;:&#34;&#34;,&#34;uic&#34;:&#34;test,tt2,tt3&#34;,&#34;id&#34;:175,&#34;callback&#34;:1,&#34;before_callback_sms&#34;:0,&#34;before_callback_mail&#34;:0,&#34;after_callback_sms&#34;:0,&#34;after_callback_mail&#34;:0}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"url\\\":\\\"\\\",\\\"uic\\\":\\\"test,tt2,tt3\\\",\\\"id\\\":175,\\\"callback\\\":1,\\\"before_callback_sms\\\":0,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":0,\\\"after_callback_mail\\\":0}\");\n                            document.getElementById('request-body6-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-6-0\">{&#34;message&#34;:&#34;action is updated, row affected: 1&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"action is updated, row affected: 1\\\"}\");\n                            document.getElementById('response-body-6-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"7top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-7-0\">{&#34;message&#34;:&#34;template 225 has been deleted&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"template 225 has been deleted\\\"}\");\n                            document.getElementById('response-body-7-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"8top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>tid</td>\n                        <td> 221</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-8-0\">[{&#34;id&#34;:893,&#34;metric&#34;:&#34;proc.num&#34;,&#34;tags&#34;:&#34;name=redis-server&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:2,&#34;func&#34;:&#34;all(#2)&#34;,&#34;op&#34;:&#34;\\u003c&#34;,&#34;right_value&#34;:&#34;1&#34;,&#34;note&#34;:&#34;FWRedis服务异常&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;tpl_id&#34;:221},{&#34;id&#34;:894,&#34;metric&#34;:&#34;proc.num&#34;,&#34;tags&#34;:&#34;name=beam.smp&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:2,&#34;func&#34;:&#34;all(#3)&#34;,&#34;op&#34;:&#34;\\u003c&#34;,&#34;right_value&#34;:&#34;1&#34;,&#34;note&#34;:&#34;FWCM进程状态异常&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;tpl_id&#34;:221},{&#34;id&#34;:895,&#34;metric&#34;:&#34;proc.num&#34;,&#34;tags&#34;:&#34;cmdline=fwlog&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:3,&#34;func&#34;:&#34;all(#5)&#34;,&#34;op&#34;:&#34;\\u003c&#34;,&#34;right_value&#34;:&#34;2&#34;,&#34;note&#34;:&#34;fwlog服务异常&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;tpl_id&#34;:221},{&#34;id&#34;:896,&#34;metric&#34;:&#34;fcd.oldworker.count&#34;,&#34;tags&#34;:&#34;&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:3,&#34;func&#34;:&#34;all(#1)&#34;,&#34;op&#34;:&#34;\\u003e&#34;,&#34;right_value&#34;:&#34;10&#34;,&#34;note&#34;:&#34;FastCache Old Worker 数量大于10&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;tpl_id&#34;:221},{&#34;id&#34;:897,&#34;metric&#34;:&#34;service.logs.jifei&#34;,&#34;tags&#34;:&#34;&#34;,&#34;max_step&#34;:1,&#34;priority&#34;:4,&#34;func&#34;:&#34;all(#3)&#34;,&#34;op&#34;:&#34;\\u003e&#34;,&#34;right_value&#34;:&#34;10&#34;,&#34;note&#34;:&#34;fastcache计费日志堆积&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;tpl_id&#34;:221},{&#34;id&#34;:898,&#34;metric&#34;:&#34;proc.num&#34;,&#34;tags&#34;:&#34;cmdline=syslog&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:4,&#34;func&#34;:&#34;all(#1)&#34;,&#34;op&#34;:&#34;\\u003c&#34;,&#34;right_value&#34;:&#34;1&#34;,&#34;note&#34;:&#34;syslog/rsyslog服务异常&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;tpl_id&#34;:221},{&#34;id&#34;:899,&#34;metric&#34;:&#34;proc.num&#34;,&#34;tags&#34;:&#34;name=fwsa2d&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:2,&#34;func&#34;:&#34;all(#2)&#34;,&#34;op&#34;:&#34;\\u003c&#34;,&#34;right_value&#34;:&#34;1&#34;,&#34;note&#34;:&#34;FWSA2服务异常&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;tpl_id&#34;:221},{&#34;id&#34;:900,&#34;metric&#34;:&#34;redis.log.null&#34;,&#34;tags&#34;:&#34;&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:2,&#34;func&#34;:&#34;all(#3)&#34;,&#34;op&#34;:&#34;!=&#34;,&#34;right_value&#34;:&#34;0&#34;,&#34;note&#34;:&#34;FWRedis同步异常&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;tpl_id&#34;:221},{&#34;id&#34;:901,&#34;metric&#34;:&#34;check.fwsa2&#34;,&#34;tags&#34;:&#34;&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:2,&#34;func&#34;:&#34;all(#3)&#34;,&#34;op&#34;:&#34;==&#34;,&#34;right_value&#34;:&#34;1&#34;,&#34;note&#34;:&#34;Fwsa2连接MQ异常&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;tpl_id&#34;:221}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":893,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"name=redis-server\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#2)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"FWRedis服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":894,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"name=beam.smp\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"FWCM进程状态异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":895,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"cmdline=fwlog\\\",\\\"max_step\\\":3,\\\"priority\\\":3,\\\"func\\\":\\\"all(#5)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"2\\\",\\\"note\\\":\\\"fwlog服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":896,\\\"metric\\\":\\\"fcd.oldworker.count\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":3,\\\"func\\\":\\\"all(#1)\\\",\\\"op\\\":\\\"\\\\u003e\\\",\\\"right_value\\\":\\\"10\\\",\\\"note\\\":\\\"FastCache Old Worker 数量大于10\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":897,\\\"metric\\\":\\\"service.logs.jifei\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":1,\\\"priority\\\":4,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"\\\\u003e\\\",\\\"right_value\\\":\\\"10\\\",\\\"note\\\":\\\"fastcache计费日志堆积\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":898,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"cmdline=syslog\\\",\\\"max_step\\\":3,\\\"priority\\\":4,\\\"func\\\":\\\"all(#1)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"syslog/rsyslog服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":899,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"name=fwsa2d\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#2)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"FWSA2服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":900,\\\"metric\\\":\\\"redis.log.null\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"!=\\\",\\\"right_value\\\":\\\"0\\\",\\\"note\\\":\\\"FWRedis同步异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":901,\\\"metric\\\":\\\"check.fwsa2\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"Fwsa2连接MQ异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221}]\");\n                            document.getElementById('response-body-8-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"9top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\n</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-9-0\" class=\"prettyprint\">{&#34;tpl_id&#34;:221,&#34;tags&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;24:00&#34;,&#34;run_begin&#34;:&#34;00:00&#34;,&#34;right_value&#34;:&#34;1&#34;,&#34;priority&#34;:1,&#34;op&#34;:&#34;==&#34;,&#34;note&#34;:&#34;this is a test&#34;,&#34;metric&#34;:&#34;agent.alive&#34;,&#34;max_step&#34;:3,&#34;func&#34;:&#34;all(#3)&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tpl_id\\\":221,\\\"tags\\\":\\\"\\\",\\\"run_end\\\":\\\"24:00\\\",\\\"run_begin\\\":\\\"00:00\\\",\\\"right_value\\\":\\\"1\\\",\\\"priority\\\":1,\\\"op\\\":\\\"==\\\",\\\"note\\\":\\\"this is a test\\\",\\\"metric\\\":\\\"agent.alive\\\",\\\"max_step\\\":3,\\\"func\\\":\\\"all(#3)\\\"}\");\n                            document.getElementById('request-body9-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-9-0\">{&#34;message&#34;:&#34;stragtegy created&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"stragtegy created\\\"}\");\n                            document.getElementById('response-body-9-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"10top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-10-0\">{&#34;id&#34;:904,&#34;metric&#34;:&#34;agent.alive&#34;,&#34;tags&#34;:&#34;&#34;,&#34;max_step&#34;:3,&#34;priority&#34;:1,&#34;func&#34;:&#34;all(#3)&#34;,&#34;op&#34;:&#34;==&#34;,&#34;right_value&#34;:&#34;1&#34;,&#34;note&#34;:&#34;this is a test&#34;,&#34;run_begin&#34;:&#34;00:00&#34;,&#34;run_end&#34;:&#34;24:00&#34;,&#34;tpl_id&#34;:221}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":904,\\\"metric\\\":\\\"agent.alive\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":1,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"this is a test\\\",\\\"run_begin\\\":\\\"00:00\\\",\\\"run_end\\\":\\\"24:00\\\",\\\"tpl_id\\\":221}\");\n                            document.getElementById('response-body-10-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"11top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\n</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-11-0\" class=\"prettyprint\">{&#34;tags&#34;:&#34;&#34;,&#34;run_end&#34;:&#34;&#34;,&#34;run_begin&#34;:&#34;&#34;,&#34;right_value&#34;:&#34;1&#34;,&#34;priority&#34;:2,&#34;op&#34;:&#34;==&#34;,&#34;note&#34;:&#34;this is a test&#34;,&#34;metric&#34;:&#34;agent.alive&#34;,&#34;max_step&#34;:3,&#34;id&#34;:904,&#34;func&#34;:&#34;all(#3)&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Apitoken\":\"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" 127.0.0.1\\r\"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"tags\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"run_begin\\\":\\\"\\\",\\\"right_value\\\":\\\"1\\\",\\\"priority\\\":2,\\\"op\\\":\\\"==\\\",\\\"note\\\":\\\"this is a test\\\",\\\"metric\\\":\\\"agent.alive\\\",\\\"max_step\\\":3,\\\"id\\\":904,\\\"func\\\":\\\"all(#3)\\\"}\");\n                            document.getElementById('request-body11-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-11-0\">{&#34;message&#34;:&#34;stragtegy:904 has been updated&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"stragtegy:904 has been updated\\\"}\");\n                            document.getElementById('response-body-11-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"12top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-12-0\">{&#34;message&#34;:&#34;strategy:904 has been deleted&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"strategy:904 has been deleted\\\"}\");\n                            document.getElementById('response-body-12-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"13top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-13-0\">[&#34;cpu.busy&#34;,&#34;cpu.cnt&#34;,&#34;cpu.guest&#34;,&#34;cpu.idle&#34;,&#34;cpu.iowait&#34;,&#34;cpu.irq&#34;,&#34;cpu.nice&#34;,&#34;cpu.softirq&#34;,&#34;cpu.steal&#34;,&#34;cpu.system&#34;,&#34;cpu.user&#34;,&#34;df.bytes.free&#34;,&#34;df.bytes.free.percent&#34;,&#34;df.bytes.total&#34;,&#34;df.bytes.used&#34;,&#34;df.bytes.used.percent&#34;,&#34;df.inodes.free&#34;,&#34;df.inodes.free.percent&#34;,&#34;df.inodes.total&#34;,&#34;df.inodes.used&#34;,&#34;df.inodes.used.percent&#34;,&#34;disk.io.avgqu-sz&#34;,&#34;disk.io.avgrq_sz&#34;,&#34;disk.io.await&#34;,&#34;disk.io.ios_in_progress&#34;,&#34;disk.io.msec_read&#34;,&#34;disk.io.msec_total&#34;,&#34;disk.io.msec_weighted_total&#34;,&#34;disk.io.msec_write&#34;,&#34;disk.io.read_bytes&#34;,&#34;disk.io.read_merged&#34;,&#34;disk.io.read_requests&#34;,&#34;disk.io.read_sectors&#34;,&#34;disk.io.svctm&#34;,&#34;disk.io.util&#34;,&#34;disk.io.write_bytes&#34;,&#34;disk.io.write_merged&#34;,&#34;disk.io.write_requests&#34;,&#34;disk.io.write_sectors&#34;,&#34;kernel.maxfiles&#34;,&#34;kernel.maxproc&#34;,&#34;load.15min&#34;,&#34;load.1min&#34;,&#34;load.5min&#34;,&#34;mem.memfree&#34;,&#34;mem.memfree.percent&#34;,&#34;mem.memtotal&#34;,&#34;mem.memused&#34;,&#34;mem.memused.percent&#34;,&#34;mem.swapfree&#34;,&#34;mem.swapfree.percent&#34;,&#34;mem.swaptotal&#34;,&#34;mem.swapused&#34;,&#34;mem.swapused.percent&#34;,&#34;net.if.in.bytes&#34;,&#34;net.if.in.compressed&#34;,&#34;net.if.in.dropped&#34;,&#34;net.if.in.errors&#34;,&#34;net.if.in.fifo.errs&#34;,&#34;net.if.in.frame.errs&#34;,&#34;net.if.in.multicast&#34;,&#34;net.if.in.packets&#34;,&#34;net.if.out.bytes&#34;,&#34;net.if.out.carrier.errs&#34;,&#34;net.if.out.collisions&#34;,&#34;net.if.out.compressed&#34;,&#34;net.if.out.dropped&#34;,&#34;net.if.out.errors&#34;,&#34;net.if.out.fifo.errs&#34;,&#34;net.if.out.packets&#34;,&#34;net.if.total.bytes&#34;,&#34;net.if.total.dropped&#34;,&#34;net.if.total.errors&#34;,&#34;net.if.total.packets&#34;,&#34;net.port.listen&#34;,&#34;proc.num&#34;,&#34;&#34;]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[\\\"cpu.busy\\\",\\\"cpu.cnt\\\",\\\"cpu.guest\\\",\\\"cpu.idle\\\",\\\"cpu.iowait\\\",\\\"cpu.irq\\\",\\\"cpu.nice\\\",\\\"cpu.softirq\\\",\\\"cpu.steal\\\",\\\"cpu.system\\\",\\\"cpu.user\\\",\\\"df.bytes.free\\\",\\\"df.bytes.free.percent\\\",\\\"df.bytes.total\\\",\\\"df.bytes.used\\\",\\\"df.bytes.used.percent\\\",\\\"df.inodes.free\\\",\\\"df.inodes.free.percent\\\",\\\"df.inodes.total\\\",\\\"df.inodes.used\\\",\\\"df.inodes.used.percent\\\",\\\"disk.io.avgqu-sz\\\",\\\"disk.io.avgrq_sz\\\",\\\"disk.io.await\\\",\\\"disk.io.ios_in_progress\\\",\\\"disk.io.msec_read\\\",\\\"disk.io.msec_total\\\",\\\"disk.io.msec_weighted_total\\\",\\\"disk.io.msec_write\\\",\\\"disk.io.read_bytes\\\",\\\"disk.io.read_merged\\\",\\\"disk.io.read_requests\\\",\\\"disk.io.read_sectors\\\",\\\"disk.io.svctm\\\",\\\"disk.io.util\\\",\\\"disk.io.write_bytes\\\",\\\"disk.io.write_merged\\\",\\\"disk.io.write_requests\\\",\\\"disk.io.write_sectors\\\",\\\"kernel.maxfiles\\\",\\\"kernel.maxproc\\\",\\\"load.15min\\\",\\\"load.1min\\\",\\\"load.5min\\\",\\\"mem.memfree\\\",\\\"mem.memfree.percent\\\",\\\"mem.memtotal\\\",\\\"mem.memused\\\",\\\"mem.memused.percent\\\",\\\"mem.swapfree\\\",\\\"mem.swapfree.percent\\\",\\\"mem.swaptotal\\\",\\\"mem.swapused\\\",\\\"mem.swapused.percent\\\",\\\"net.if.in.bytes\\\",\\\"net.if.in.compressed\\\",\\\"net.if.in.dropped\\\",\\\"net.if.in.errors\\\",\\\"net.if.in.fifo.errs\\\",\\\"net.if.in.frame.errs\\\",\\\"net.if.in.multicast\\\",\\\"net.if.in.packets\\\",\\\"net.if.out.bytes\\\",\\\"net.if.out.carrier.errs\\\",\\\"net.if.out.collisions\\\",\\\"net.if.out.compressed\\\",\\\"net.if.out.dropped\\\",\\\"net.if.out.errors\\\",\\\"net.if.out.fifo.errs\\\",\\\"net.if.out.packets\\\",\\\"net.if.total.bytes\\\",\\\"net.if.total.dropped\\\",\\\"net.if.total.errors\\\",\\\"net.if.total.packets\\\",\\\"net.port.listen\\\",\\\"proc.num\\\",\\\"\\\"]\");\n                            document.getElementById('response-body-13-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"14top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\n</td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>q</td>\n                        <td> a</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-14-0\">[{&#34;id&#34;:63,&#34;tpl_name&#34;:&#34;tplAa&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:0,&#34;create_user&#34;:&#34;&#34;},{&#34;id&#34;:53,&#34;tpl_name&#34;:&#34;TplBa&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:0,&#34;create_user&#34;:&#34;&#34;},{&#34;id&#34;:220,&#34;tpl_name&#34;:&#34;TplCa&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:0,&#34;create_user&#34;:&#34;&#34;},{&#34;id&#34;:42,&#34;tpl_name&#34;:&#34;basic&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:0,&#34;create_user&#34;:&#34;&#34;},{&#34;id&#34;:149,&#34;tpl_name&#34;:&#34;TplDa&#34;,&#34;parent_id&#34;:0,&#34;action_id&#34;:0,&#34;create_user&#34;:&#34;&#34;}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":63,\\\"tpl_name\\\":\\\"tplAa\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"},{\\\"id\\\":53,\\\"tpl_name\\\":\\\"TplBa\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"},{\\\"id\\\":220,\\\"tpl_name\\\":\\\"TplCa\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"},{\\\"id\\\":42,\\\"tpl_name\\\":\\\"basic\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"},{\\\"id\\\":149,\\\"tpl_name\\\":\\\"TplDa\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"}]\");\n                            document.getElementById('response-body-14-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>\n"
  },
  {
    "path": "docs/doc/template.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/template/178\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/template/178\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/user/auth_session\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/user/auth_session\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"session is vaild!\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/template\",\n      \"Calls\": [\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/template\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":1,\\\"tpl_name\\\":\\\"cpu.board\\\",\\\"parent_id\\\":0,\\\"action_id\\\":5,\\\"create_user\\\":\\\"usera\\\"},{\\\"id\\\":2,\\\"tpl_name\\\":\\\"traffic checking\\\",\\\"parent_id\\\":0,\\\"action_id\\\":6,\\\"create_user\\\":\\\"userb\\\"},{\\\"id\\\":3,\\\"tpl_name\\\":\\\"cputest\\\",\\\"parent_id\\\":0,\\\"action_id\\\":7,\\\"create_user\\\":\\\"userc\\\"},{\\\"id\\\":5,\\\"tpl_name\\\":\\\"all metrics base\\\",\\\"parent_id\\\":0,\\\"action_id\\\":12,\\\"create_user\\\":\\\"root\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/template\",\n      \"Calls\": [\n        {\n          \"Id\": 3,\n          \"CurrentPath\": \"/api/v1/template\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": \"{\\\"action\\\":{\\\"id\\\":141,\\\"uic\\\":\\\"admin,mm1\\\",\\\"url\\\":\\\"\\\",\\\"callback\\\":0,\\\"before_callback_sms\\\":0,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":0,\\\"after_callback_mail\\\":0},\\\"stratges\\\":[{\\\"id\\\":686,\\\"metric\\\":\\\"xxx.check\\\",\\\"tags\\\":\\\"name=xxx\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#2)\\\",\\\"op\\\":\\\"<\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"xxx服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":178},{\\\"id\\\":687,\\\"metric\\\":\\\"xxx.sync\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"!=\\\",\\\"right_value\\\":\\\"0\\\",\\\"note\\\":\\\"XXX同步异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":178},{\\\"id\\\":688,\\\"metric\\\":\\\"bbb.check.mq\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"bbb连接MQ异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":178},{\\\"id\\\":793,\\\"metric\\\":\\\"aaa.proc.num\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"aaaa 进程大于5\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":178}],\\\"template\\\":{\\\"id\\\":178,\\\"tpl_name\\\":\\\"TemplateA\\\",\\\"parent_id\\\":0,\\\"action_id\\\":141,\\\"create_user\\\":\\\"root\\\"}}\",\n          \"RequestBody\": \"{\\\"parent_id\\\":0,\\\"name\\\":\\\"AtmpForTesting\\\"}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"template created\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/template/action\",\n      \"Calls\": [\n        {\n          \"Id\": 4,\n          \"CurrentPath\": \"/api/v1/template/action\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"url\\\":\\\"\\\",\\\"uic\\\":\\\"test,tt2\\\",\\\"tpl_id\\\":225,\\\"callback\\\":1,\\\"before_callback_sms\\\":0,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":0,\\\"after_callback_mail\\\":0}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"action is created and bind to template: 225\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/template\",\n      \"Calls\": [\n        {\n          \"Id\": 5,\n          \"CurrentPath\": \"/api/v1/template\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tpl_id\\\":225,\\\"parent_id\\\":0,\\\"name\\\":\\\"AtmpForTesting2\\\"}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"template updated\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/template/action\",\n      \"Calls\": [\n        {\n          \"Id\": 6,\n          \"CurrentPath\": \"/api/v1/template/action\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"url\\\":\\\"\\\",\\\"uic\\\":\\\"test,tt2,tt3\\\",\\\"id\\\":175,\\\"callback\\\":1,\\\"before_callback_sms\\\":0,\\\"before_callback_mail\\\":0,\\\"after_callback_sms\\\":0,\\\"after_callback_mail\\\":0}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"action is updated, row affected: 1\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"DELETE\",\n      \"Path\": \"/api/v1/template/225\",\n      \"Calls\": [\n        {\n          \"Id\": 7,\n          \"CurrentPath\": \"/api/v1/template/225\",\n          \"MethodType\": \"DELETE\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"template 225 has been deleted\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/strategy\",\n      \"Calls\": [\n        {\n          \"Id\": 8,\n          \"CurrentPath\": \"/api/v1/strategy\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"tid\": \"221\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":893,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"name=redis-server\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#2)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"FWRedis服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":894,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"name=beam.smp\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"FWCM进程状态异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":895,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"cmdline=fwlog\\\",\\\"max_step\\\":3,\\\"priority\\\":3,\\\"func\\\":\\\"all(#5)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"2\\\",\\\"note\\\":\\\"fwlog服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":896,\\\"metric\\\":\\\"fcd.oldworker.count\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":3,\\\"func\\\":\\\"all(#1)\\\",\\\"op\\\":\\\"\\\\u003e\\\",\\\"right_value\\\":\\\"10\\\",\\\"note\\\":\\\"FastCache Old Worker 数量大于10\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":897,\\\"metric\\\":\\\"service.logs.jifei\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":1,\\\"priority\\\":4,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"\\\\u003e\\\",\\\"right_value\\\":\\\"10\\\",\\\"note\\\":\\\"fastcache计费日志堆积\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":898,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"cmdline=syslog\\\",\\\"max_step\\\":3,\\\"priority\\\":4,\\\"func\\\":\\\"all(#1)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"syslog/rsyslog服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":899,\\\"metric\\\":\\\"proc.num\\\",\\\"tags\\\":\\\"name=fwsa2d\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#2)\\\",\\\"op\\\":\\\"\\\\u003c\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"FWSA2服务异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":900,\\\"metric\\\":\\\"redis.log.null\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"!=\\\",\\\"right_value\\\":\\\"0\\\",\\\"note\\\":\\\"FWRedis同步异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221},{\\\"id\\\":901,\\\"metric\\\":\\\"check.fwsa2\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":2,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"Fwsa2连接MQ异常\\\",\\\"run_begin\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"tpl_id\\\":221}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/strategy\",\n      \"Calls\": [\n        {\n          \"Id\": 9,\n          \"CurrentPath\": \"/api/v1/strategy\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tpl_id\\\":221,\\\"tags\\\":\\\"\\\",\\\"run_end\\\":\\\"24:00\\\",\\\"run_begin\\\":\\\"00:00\\\",\\\"right_value\\\":\\\"1\\\",\\\"priority\\\":1,\\\"op\\\":\\\"==\\\",\\\"note\\\":\\\"this is a test\\\",\\\"metric\\\":\\\"agent.alive\\\",\\\"max_step\\\":3,\\\"func\\\":\\\"all(#3)\\\"}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"stragtegy created\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/strategy/904\",\n      \"Calls\": [\n        {\n          \"Id\": 10,\n          \"CurrentPath\": \"/api/v1/strategy/904\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"id\\\":904,\\\"metric\\\":\\\"agent.alive\\\",\\\"tags\\\":\\\"\\\",\\\"max_step\\\":3,\\\"priority\\\":1,\\\"func\\\":\\\"all(#3)\\\",\\\"op\\\":\\\"==\\\",\\\"right_value\\\":\\\"1\\\",\\\"note\\\":\\\"this is a test\\\",\\\"run_begin\\\":\\\"00:00\\\",\\\"run_end\\\":\\\"24:00\\\",\\\"tpl_id\\\":221}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/strategy\",\n      \"Calls\": [\n        {\n          \"Id\": 11,\n          \"CurrentPath\": \"/api/v1/strategy\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"tags\\\":\\\"\\\",\\\"run_end\\\":\\\"\\\",\\\"run_begin\\\":\\\"\\\",\\\"right_value\\\":\\\"1\\\",\\\"priority\\\":2,\\\"op\\\":\\\"==\\\",\\\"note\\\":\\\"this is a test\\\",\\\"metric\\\":\\\"agent.alive\\\",\\\"max_step\\\":3,\\\"id\\\":904,\\\"func\\\":\\\"all(#3)\\\"}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"stragtegy:904 has been updated\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"DELETE\",\n      \"Path\": \"/api/v1/strategy/904\",\n      \"Calls\": [\n        {\n          \"Id\": 12,\n          \"CurrentPath\": \"/api/v1/strategy/904\",\n          \"MethodType\": \"DELETE\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"strategy:904 has been deleted\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/metric/default_list\",\n      \"Calls\": [\n        {\n          \"Id\": 13,\n          \"CurrentPath\": \"/api/v1/metric/default_list\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[\\\"cpu.busy\\\",\\\"cpu.cnt\\\",\\\"cpu.guest\\\",\\\"cpu.idle\\\",\\\"cpu.iowait\\\",\\\"cpu.irq\\\",\\\"cpu.nice\\\",\\\"cpu.softirq\\\",\\\"cpu.steal\\\",\\\"cpu.system\\\",\\\"cpu.user\\\",\\\"df.bytes.free\\\",\\\"df.bytes.free.percent\\\",\\\"df.bytes.total\\\",\\\"df.bytes.used\\\",\\\"df.bytes.used.percent\\\",\\\"df.inodes.free\\\",\\\"df.inodes.free.percent\\\",\\\"df.inodes.total\\\",\\\"df.inodes.used\\\",\\\"df.inodes.used.percent\\\",\\\"disk.io.avgqu-sz\\\",\\\"disk.io.avgrq_sz\\\",\\\"disk.io.await\\\",\\\"disk.io.ios_in_progress\\\",\\\"disk.io.msec_read\\\",\\\"disk.io.msec_total\\\",\\\"disk.io.msec_weighted_total\\\",\\\"disk.io.msec_write\\\",\\\"disk.io.read_bytes\\\",\\\"disk.io.read_merged\\\",\\\"disk.io.read_requests\\\",\\\"disk.io.read_sectors\\\",\\\"disk.io.svctm\\\",\\\"disk.io.util\\\",\\\"disk.io.write_bytes\\\",\\\"disk.io.write_merged\\\",\\\"disk.io.write_requests\\\",\\\"disk.io.write_sectors\\\",\\\"kernel.maxfiles\\\",\\\"kernel.maxproc\\\",\\\"load.15min\\\",\\\"load.1min\\\",\\\"load.5min\\\",\\\"mem.memfree\\\",\\\"mem.memfree.percent\\\",\\\"mem.memtotal\\\",\\\"mem.memused\\\",\\\"mem.memused.percent\\\",\\\"mem.swapfree\\\",\\\"mem.swapfree.percent\\\",\\\"mem.swaptotal\\\",\\\"mem.swapused\\\",\\\"mem.swapused.percent\\\",\\\"net.if.in.bytes\\\",\\\"net.if.in.compressed\\\",\\\"net.if.in.dropped\\\",\\\"net.if.in.errors\\\",\\\"net.if.in.fifo.errs\\\",\\\"net.if.in.frame.errs\\\",\\\"net.if.in.multicast\\\",\\\"net.if.in.packets\\\",\\\"net.if.out.bytes\\\",\\\"net.if.out.carrier.errs\\\",\\\"net.if.out.collisions\\\",\\\"net.if.out.compressed\\\",\\\"net.if.out.dropped\\\",\\\"net.if.out.errors\\\",\\\"net.if.out.fifo.errs\\\",\\\"net.if.out.packets\\\",\\\"net.if.total.bytes\\\",\\\"net.if.total.dropped\\\",\\\"net.if.total.errors\\\",\\\"net.if.total.packets\\\",\\\"net.port.listen\\\",\\\"proc.num\\\",\\\"\\\"]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/template_simple\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/template_simple\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"q\": \"a\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":63,\\\"tpl_name\\\":\\\"AllCacheServer\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"},{\\\"id\\\":53,\\\"tpl_name\\\":\\\"arch2_monitor\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"},{\\\"id\\\":220,\\\"tpl_name\\\":\\\"Bandwidth_trends\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"},{\\\"id\\\":42,\\\"tpl_name\\\":\\\"basic\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"},{\\\"id\\\":149,\\\"tpl_name\\\":\\\"bossapi\\\",\\\"parent_id\\\":0,\\\"action_id\\\":0,\\\"create_user\\\":\\\"\\\"}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/doc/user.html",
    "content": "<!DOCTYPE html>\n<html>\n<head lang=\"en\">\n    <title> API Documentation </title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css\">\n    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>\n\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css\">\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>\n\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js\"></script>\n    <style type=\"text/css\">\n        body {\n            font-family: 'Roboto', sans-serif;\n        }\n        .hidden {\n            display:none;\n        }\n        pre {\n            outline: 1px solid #ccc;\n            padding: 5px; margin: 5px;\n        }\n\n        .string { color: green; }\n        .number { color: darkorange; }\n        .boolean { color: blue; }\n        .null { color: magenta; }\n        .key { color: red; }\n\n    </style>\n    <style type=\"text/css\">\n        pre.prettyprint {\n            border: 1px solid #ccc;\n            margin-bottom: 0;\n            padding: 9.5px;\n        }\n    </style>\n    <script>\n\n        function syntaxHighlight(json) {\n            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n            return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n                var cls = 'number';\n                if (/^\"/.test(match)) {\n                    if (/:$/.test(match)) {\n                        cls = 'key';\n                    } else {\n                        cls = 'string';\n                    }\n                } else if (/true|false/.test(match)) {\n                    cls = 'boolean';\n                } else if (/null/.test(match)) {\n                    cls = 'null';\n                }\n                return '<span class=\"' + cls + '\">' + match + '</span>';\n            });\n        }\n\n        function spaceJson(json){\n            var validJson = JSON.parse(json);\n            return JSON.stringify(validJson, undefined, 4);\n        }\n    </script>\n\n</head>\n<body>\n<nav class=\"navbar navbar-default navbar-fixed-top\">\n    <div class=\"container-fluid\">\n\n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\"\n                    data-target=\"#bs-example-navbar-collapse-1\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"#\">Gin</a>\n            <p class=\"navbar-text\">Developed by Gophers at <a href=\"http://betacraft.co\">Betacraft</a></p>\n        </div>\n\n\n    </div>\n\n</nav>\n<div class=\"container-fluid\" style=\"margin-top: 70px;margin-bottom: 20px;\">\n    <div class=\"container-fluid\">\n    <div class=\"col-md-4\">\n        <div class=\"panel panel-default\">\n              <div class=\"panel-heading\">Base Urls</div>\n              <div class=\"panel-body\">\n\n                    <p>Production : <strong>/api/v1</strong></p>\n\n                    <p>Staging : <strong>/api/v1</strong></p>\n\n              </div>\n            </div>\n        <ul class=\"nav nav-pills nav-stacked\" role=\"tablist\">\n\n                <li role=\"presentation\"><a href=\"#0top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/user/create</a></li>\n\n                <li role=\"presentation\"><a href=\"#1top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/user/update</a></li>\n\n                <li role=\"presentation\"><a href=\"#2top\" role=\"tab\" data-toggle=\"tab\">PUT : /api/v1/user/cgpasswd</a></li>\n\n                <li role=\"presentation\"><a href=\"#3top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/user/users</a></li>\n\n                <li role=\"presentation\"><a href=\"#4top\" role=\"tab\" data-toggle=\"tab\">POST : /api/v1/user/login</a></li>\n\n                <li role=\"presentation\"><a href=\"#5top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/user/logout</a></li>\n\n                <li role=\"presentation\"><a href=\"#6top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/user/auth_session</a></li>\n\n                <li role=\"presentation\"><a href=\"#7top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/user/current</a></li>\n\n                <li role=\"presentation\"><a href=\"#8top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/user/u/3</a></li>\n\n                <li role=\"presentation\"><a href=\"#9top\" role=\"tab\" data-toggle=\"tab\">GET : /api/v1/user/u/4</a></li>\n\n        <ul>\n    </div>\n    <div class=\"col-md-8 tab-content\">\n\n        <div id=\"0top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-0\" class=\"prettyprint\">{&#34;name&#34;: &#34;test&#34;,&#34;password&#34;: &#34;test&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" \"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"name\\\": \\\"test\\\",\\\"password\\\": \\\"test\\\"}\");\n                            document.getElementById('request-body0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">400</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-0\">{&#34;error&#34;:&#34;Key: &#39;APIUserInput.Cnname&#39; Error:Field validation for &#39;Cnname&#39; failed on the &#39;required&#39; tag\\nKey: &#39;APIUserInput.Email&#39; Error:Field validation for &#39;Email&#39; failed on the &#39;required&#39; tag&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"Key: 'APIUserInput.Cnname' Error:Field validation for 'Cnname' failed on the 'required' tag\\\\nKey: 'APIUserInput.Email' Error:Field validation for 'Email' failed on the 'required' tag\\\"}\");\n                            document.getElementById('response-body-0-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-0-1\" class=\"prettyprint\">{&#34;name&#34;: &#34;owltester&#34;,&#34;password&#34;: &#34;mypassword&#34;, &#34;cnname&#34;: &#34;翱鶚&#34;, &#34;email&#34;: &#34;root123@cepave.com&#34;, &#34;im&#34;: &#34;44955834958&#34;, &#34;phone&#34;: &#34;99999999999&#34;, &#34;qq&#34;: &#34;904394234239&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Content-Type\":\" application/json\\r\",\"X-Forwarded-For\":\" \"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"name\\\": \\\"owltester\\\",\\\"password\\\": \\\"mypassword\\\", \\\"cnname\\\": \\\"翱鶚\\\", \\\"email\\\": \\\"root123@cepave.com\\\", \\\"im\\\": \\\"44955834958\\\", \\\"phone\\\": \\\"99999999999\\\", \\\"qq\\\": \\\"904394234239\\\"}\");\n                            document.getElementById('request-body0-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-0-1\">{&#34;name&#34;:&#34;owltester&#34;,&#34;sig&#34;:&#34;9b42a728c0ea11e690c5001500c6ca5a&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"name\\\":\\\"owltester\\\",\\\"sig\\\":\\\"9b42a728c0ea11e690c5001500c6ca5a\\\"}\");\n                            document.getElementById('response-body-0-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"1top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=test1; sig=d4f71cba377911e699d60242ac110010\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-1-0\" class=\"prettyprint\">{&#34;name&#34;: &#34;test1&#34;,&#34;password&#34;: &#34;test1&#34;, &#34;cnname&#34;: &#34;翱鶚Test&#34;, &#34;email&#34;: &#34;root123@cepave.com&#34;, &#34;im&#34;: &#34;44955834958&#34;, &#34;phone&#34;: &#34;99999999999&#34;, &#34;qq&#34;: &#34;904394234239&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Content-Type\":\" application/json\\r\",\"Cookie\":\" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\"X-Forwarded-For\":\" \"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"name\\\": \\\"test1\\\",\\\"password\\\": \\\"test1\\\", \\\"cnname\\\": \\\"翱鶚Test\\\", \\\"email\\\": \\\"root123@cepave.com\\\", \\\"im\\\": \\\"44955834958\\\", \\\"phone\\\": \\\"99999999999\\\", \\\"qq\\\": \\\"904394234239\\\"}\");\n                            document.getElementById('request-body1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-1-0\">{&#34;message&#34;:&#34;user info updated&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"user info updated\\\"}\");\n                            document.getElementById('response-body-1-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"2top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td>  application/json\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=test1; sig=d4f71cba377911e699d60242ac110010\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p> <H4> Request Body </H4> </p>\n                <pre id=\"request-body-2-0\" class=\"prettyprint\">{&#34;new_password&#34;: &#34;test1&#34;, &#34;old_password&#34;: &#34;test1&#34;}</pre>\n                <script>\n\n                    var requestHeader ={\"Content-Type\":\" application/json\\r\",\"Cookie\":\" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\"X-Forwarded-For\":\" \"};\n\n                    if (requestHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"new_password\\\": \\\"test1\\\", \\\"old_password\\\": \\\"test1\\\"}\");\n                            document.getElementById('request-body2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-2-0\">{&#34;message&#34;:&#34;password updated!&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"password updated!\\\"}\");\n                            document.getElementById('response-body-2-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"3top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=test1; sig=d4f71cba377911e699d60242ac110010\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-3-0\">[{&#34;id&#34;:1,&#34;name&#34;:&#34;root&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:2},{&#34;id&#34;:2,&#34;name&#34;:&#34;yao104&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:3,&#34;name&#34;:&#34;xiecz&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:4,&#34;name&#34;:&#34;test1&#34;,&#34;cnname&#34;:&#34;翱鶚Test&#34;,&#34;email&#34;:&#34;root123@cepave.com&#34;,&#34;phone&#34;:&#34;99999999999&#34;,&#34;im&#34;:&#34;44955834958&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:5,&#34;name&#34;:&#34;don&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:6,&#34;name&#34;:&#34;masato&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:7,&#34;name&#34;:&#34;cepave1&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:9,&#34;name&#34;:&#34;test2&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:10,&#34;name&#34;:&#34;kordan&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:11,&#34;name&#34;:&#34;laurence&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:12,&#34;name&#34;:&#34;kelly&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:13,&#34;name&#34;:&#34;masato25&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0},{&#34;id&#34;:14,&#34;name&#34;:&#34;myhung&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:1},{&#34;id&#34;:32,&#34;name&#34;:&#34;owltester&#34;,&#34;cnname&#34;:&#34;翱鶚&#34;,&#34;email&#34;:&#34;root123@cepave.com&#34;,&#34;phone&#34;:&#34;99999999999&#34;,&#34;im&#34;:&#34;44955834958&#34;,&#34;qq&#34;:&#34;904394234239&#34;,&#34;role&#34;:0}]</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"[{\\\"id\\\":1,\\\"name\\\":\\\"root\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":2},{\\\"id\\\":2,\\\"name\\\":\\\"yao104\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":3,\\\"name\\\":\\\"xiecz\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":4,\\\"name\\\":\\\"test1\\\",\\\"cnname\\\":\\\"翱鶚Test\\\",\\\"email\\\":\\\"root123@cepave.com\\\",\\\"phone\\\":\\\"99999999999\\\",\\\"im\\\":\\\"44955834958\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":5,\\\"name\\\":\\\"don\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":6,\\\"name\\\":\\\"masato\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":7,\\\"name\\\":\\\"cepave1\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":9,\\\"name\\\":\\\"test2\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":10,\\\"name\\\":\\\"kordan\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":11,\\\"name\\\":\\\"laurence\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":12,\\\"name\\\":\\\"kelly\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":13,\\\"name\\\":\\\"masato25\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":14,\\\"name\\\":\\\"myhung\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":1},{\\\"id\\\":32,\\\"name\\\":\\\"owltester\\\",\\\"cnname\\\":\\\"翱鶚\\\",\\\"email\\\":\\\"root123@cepave.com\\\",\\\"phone\\\":\\\"99999999999\\\",\\\"im\\\":\\\"44955834958\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0}]\");\n                            document.getElementById('response-body-3-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"4top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>name</td>\n                        <td> gg123</td>\n                    </tr>\n\n                    <tr>\n                        <td>password</td>\n                        <td> willnotpass</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">400</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-0\">{&#34;error&#34;:&#34;password error&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"password error\\\"}\");\n                            document.getElementById('response-body-4-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n                <p> <H4> URL Params </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>name</td>\n                        <td> test2</td>\n                    </tr>\n\n                    <tr>\n                        <td>password</td>\n                        <td> test2</td>\n                    </tr>\n\n                </table>\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-4-1\">{&#34;sig&#34;:&#34;9d791331c0ea11e690c5001500c6ca5a&#34;,&#34;name&#34;:&#34;test2&#34;,&#34;admin&#34;:false}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"sig\\\":\\\"9d791331c0ea11e690c5001500c6ca5a\\\",\\\"name\\\":\\\"test2\\\",\\\"admin\\\":false}\");\n                            document.getElementById('response-body-4-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"5top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=test2; sig=9d791331c0ea11e690c5001500c6ca5a\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-5-0\">{&#34;message&#34;:&#34;logout successful&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"logout successful\\\"}\");\n                            document.getElementById('response-body-5-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"6top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=test1; sig=d4f71cba377911e699d60242ac110010\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-6-0\">{&#34;message&#34;:&#34;session is vaild!&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"message\\\":\\\"session is vaild!\\\"}\");\n                            document.getElementById('response-body-6-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Cookie</td>\n                        <td>  name=testtest; sig=9a84ae1d377911e699d60242ac110010\r</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  </td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">401</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type,Token</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-6-1\">{&#34;error&#34;:&#34;not found this user&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Headers\":\"Content-Type,Token\",\"Access-Control-Allow-Origin\":\"*\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"not found this user\\\"}\");\n                            document.getElementById('response-body-6-1').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"7top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-7-0\">{&#34;id&#34;:2,&#34;name&#34;:&#34;root&#34;,&#34;cnname&#34;:&#34;&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;&#34;,&#34;role&#34;:2}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":2,\\\"name\\\":\\\"root\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"\\\",\\\"role\\\":2}\");\n                            document.getElementById('response-body-7-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"8top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">417</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-8-0\">{&#34;error&#34;:&#34;record not found&#34;}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"error\\\":\\\"record not found\\\"}\");\n                            document.getElementById('response-body-8-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n        <div id=\"9top\"  role=\"tabpanel\" class=\"tab-pane col-md-10\">\n\n\n                <p> <H4> Request Headers </H4> </p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Apitoken</td>\n                        <td> {&#34;name&#34;:&#34;root&#34;,&#34;sig&#34;:&#34;427d6803b78311e68afd0242ac130006&#34;}</td>\n                    </tr>\n\n                    <tr>\n                        <td>X-Forwarded-For</td>\n                        <td>  127.0.0.1\r</td>\n                    </tr>\n\n                </table>\n\n\n\n\n                <p><h4> Response Code</h4></p>\n                <pre class=\"prettyprint lang-json\">200</pre>\n\n                <p><h4> Response Headers</h4></p>\n                <table class=\"table table-bordered table-striped\">\n                    <tr>\n                        <th>Key</th>\n                        <th>Value</th>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Credentials</td>\n                        <td> true</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Headers</td>\n                        <td> Content-Type, Content-Length, Apitoken</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Methods</td>\n                        <td> POST, GET, OPTIONS, PUT, DELETE, UPDATE</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Allow-Origin</td>\n                        <td> *</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Expose-Headers</td>\n                        <td> Content-Length</td>\n                    </tr>\n\n                    <tr>\n                        <td>Access-Control-Max-Age</td>\n                        <td> 86400</td>\n                    </tr>\n\n                    <tr>\n                        <td>Content-Type</td>\n                        <td> application/json; charset=utf-8</td>\n                    </tr>\n\n                </table>\n\n\n                <p> <H4> Response Body </H4> </p>\n                <pre class=\"prettyprint\" id=\"response-body-9-0\">{&#34;id&#34;:4,&#34;name&#34;:&#34;userA&#34;,&#34;cnname&#34;:&#34;tear&#34;,&#34;email&#34;:&#34;&#34;,&#34;phone&#34;:&#34;&#34;,&#34;im&#34;:&#34;&#34;,&#34;qq&#34;:&#34;&#34;,&#34;role&#34;:0}</pre>\n                <script>\n\n                    var responseHeader ={\"Access-Control-Allow-Credentials\":\"true\",\"Access-Control-Allow-Headers\":\"Content-Type, Content-Length, Apitoken\",\"Access-Control-Allow-Methods\":\"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\"Access-Control-Allow-Origin\":\"*\",\"Access-Control-Expose-Headers\":\"Content-Length\",\"Access-Control-Max-Age\":\"86400\",\"Content-Type\":\"application/json; charset=utf-8\"};\n\n                    if (responseHeader[\"Content-Type\"] === \"application/json\"){\n                        try {\n                            var jsonStr = spaceJson(\"{\\\"id\\\":4,\\\"name\\\":\\\"userA\\\",\\\"cnname\\\":\\\"tear\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"\\\",\\\"role\\\":0}\");\n                            document.getElementById('response-body-9-0').innerHTML = syntaxHighlight(jsonStr);\n                        } catch (e) {\n\n                        }\n                    }\n                </script>\n\n                <hr>\n\n        </div>\n\n    </div>\n</div>\n</div>\n<hr>\n</body>\n</html>\n"
  },
  {
    "path": "docs/doc/user.html.json",
    "content": "{\n  \"ApiSpecs\": [\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/user/create\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/user/create\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"name\\\": \\\"test\\\",\\\"password\\\": \\\"test\\\"}\",\n          \"ResponseBody\": \"{\\\"error\\\":\\\"Key: 'APIUserInput.Cnname' Error:Field validation for 'Cnname' failed on the 'required' tag\\\\nKey: 'APIUserInput.Email' Error:Field validation for 'Email' failed on the 'required' tag\\\"}\",\n          \"ResponseCode\": 400\n        },\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/user/create\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Content-Type\": \" application/json\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"name\\\": \\\"owltester\\\",\\\"password\\\": \\\"mypassword\\\", \\\"cnname\\\": \\\"翱鶚\\\", \\\"email\\\": \\\"root123@cepave.com\\\", \\\"im\\\": \\\"44955834958\\\", \\\"phone\\\": \\\"99999999999\\\", \\\"qq\\\": \\\"904394234239\\\"}\",\n          \"ResponseBody\": \"{\\\"name\\\":\\\"owltester\\\",\\\"sig\\\":\\\"9b42a728c0ea11e690c5001500c6ca5a\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/user/update\",\n      \"Calls\": [\n        {\n          \"Id\": 2,\n          \"CurrentPath\": \"/api/v1/user/update\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Content-Type\": \" application/json\\r\",\n            \"Cookie\": \" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"name\\\": \\\"test1\\\",\\\"password\\\": \\\"test1\\\", \\\"cnname\\\": \\\"翱鶚Test\\\", \\\"email\\\": \\\"root123@cepave.com\\\", \\\"im\\\": \\\"44955834958\\\", \\\"phone\\\": \\\"99999999999\\\", \\\"qq\\\": \\\"904394234239\\\"}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"user info updated\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"PUT\",\n      \"Path\": \"/api/v1/user/cgpasswd\",\n      \"Calls\": [\n        {\n          \"Id\": 3,\n          \"CurrentPath\": \"/api/v1/user/cgpasswd\",\n          \"MethodType\": \"PUT\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Content-Type\": \" application/json\\r\",\n            \"Cookie\": \" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"{\\\"new_password\\\": \\\"test1\\\", \\\"old_password\\\": \\\"test1\\\"}\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"password updated!\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/user/users\",\n      \"Calls\": [\n        {\n          \"Id\": 4,\n          \"CurrentPath\": \"/api/v1/user/users\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Cookie\": \" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"[{\\\"id\\\":1,\\\"name\\\":\\\"root\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":2},{\\\"id\\\":2,\\\"name\\\":\\\"yao104\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":3,\\\"name\\\":\\\"xiecz\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":4,\\\"name\\\":\\\"test1\\\",\\\"cnname\\\":\\\"翱鶚Test\\\",\\\"email\\\":\\\"root123@cepave.com\\\",\\\"phone\\\":\\\"99999999999\\\",\\\"im\\\":\\\"44955834958\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":5,\\\"name\\\":\\\"don\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":6,\\\"name\\\":\\\"masato\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":7,\\\"name\\\":\\\"cepave1\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":9,\\\"name\\\":\\\"test2\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":10,\\\"name\\\":\\\"kordan\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":11,\\\"name\\\":\\\"laurence\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":12,\\\"name\\\":\\\"kelly\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":13,\\\"name\\\":\\\"masato25\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0},{\\\"id\\\":14,\\\"name\\\":\\\"myhung\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":1},{\\\"id\\\":32,\\\"name\\\":\\\"owltester\\\",\\\"cnname\\\":\\\"翱鶚\\\",\\\"email\\\":\\\"root123@cepave.com\\\",\\\"phone\\\":\\\"99999999999\\\",\\\"im\\\":\\\"44955834958\\\",\\\"qq\\\":\\\"904394234239\\\",\\\"role\\\":0}]\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"POST\",\n      \"Path\": \"/api/v1/user/login\",\n      \"Calls\": [\n        {\n          \"Id\": 5,\n          \"CurrentPath\": \"/api/v1/user/login\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"name\": \"gg123\",\n            \"password\": \"willnotpass\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"error\\\":\\\"password error\\\"}\",\n          \"ResponseCode\": 400\n        },\n        {\n          \"Id\": 6,\n          \"CurrentPath\": \"/api/v1/user/login\",\n          \"MethodType\": \"POST\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {\n            \"name\": \"test2\",\n            \"password\": \"test2\"\n          },\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"sig\\\":\\\"9d791331c0ea11e690c5001500c6ca5a\\\",\\\"name\\\":\\\"test2\\\",\\\"admin\\\":false}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/user/logout\",\n      \"Calls\": [\n        {\n          \"Id\": 8,\n          \"CurrentPath\": \"/api/v1/user/logout\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Cookie\": \" name=test2; sig=9d791331c0ea11e690c5001500c6ca5a\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"logout successful\\\"}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/user/auth_session\",\n      \"Calls\": [\n        {\n          \"Id\": 9,\n          \"CurrentPath\": \"/api/v1/user/auth_session\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Cookie\": \" name=test1; sig=d4f71cba377911e699d60242ac110010\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"message\\\":\\\"session is vaild!\\\"}\",\n          \"ResponseCode\": 200\n        },\n        {\n          \"Id\": 10,\n          \"CurrentPath\": \"/api/v1/user/auth_session\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Cookie\": \" name=testtest; sig=9a84ae1d377911e699d60242ac110010\\r\",\n            \"X-Forwarded-For\": \" \"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Headers\": \"Content-Type,Token\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"error\\\":\\\"not found this user\\\"}\",\n          \"ResponseCode\": 401\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/user/current\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/user/current\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"id\\\":2,\\\"name\\\":\\\"root\\\",\\\"cnname\\\":\\\"\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"\\\",\\\"role\\\":2}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/user/u/3\",\n      \"Calls\": [\n        {\n          \"Id\": 0,\n          \"CurrentPath\": \"/api/v1/user/u/3\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"error\\\":\\\"record not found\\\"}\",\n          \"ResponseCode\": 417\n        }\n      ]\n    },\n    {\n      \"HttpVerb\": \"GET\",\n      \"Path\": \"/api/v1/user/u/4\",\n      \"Calls\": [\n        {\n          \"Id\": 1,\n          \"CurrentPath\": \"/api/v1/user/u/4\",\n          \"MethodType\": \"GET\",\n          \"PostForm\": null,\n          \"RequestHeader\": {\n            \"Apitoken\": \"{\\\"name\\\":\\\"root\\\",\\\"sig\\\":\\\"427d6803b78311e68afd0242ac130006\\\"}\",\n            \"X-Forwarded-For\": \" 127.0.0.1\\r\"\n          },\n          \"CommonRequestHeaders\": null,\n          \"ResponseHeader\": {\n            \"Access-Control-Allow-Credentials\": \"true\",\n            \"Access-Control-Allow-Headers\": \"Content-Type, Content-Length, Apitoken\",\n            \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS, PUT, DELETE, UPDATE\",\n            \"Access-Control-Allow-Origin\": \"*\",\n            \"Access-Control-Expose-Headers\": \"Content-Length\",\n            \"Access-Control-Max-Age\": \"86400\",\n            \"Content-Type\": \"application/json; charset=utf-8\"\n          },\n          \"RequestUrlParams\": {},\n          \"RequestBody\": \"\",\n          \"ResponseBody\": \"{\\\"id\\\":4,\\\"name\\\":\\\"userA\\\",\\\"cnname\\\":\\\"tear\\\",\\\"email\\\":\\\"\\\",\\\"phone\\\":\\\"\\\",\\\"im\\\":\\\"\\\",\\\"qq\\\":\\\"\\\",\\\"role\\\":0}\",\n          \"ResponseCode\": 200\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/index.html",
    "content": "---\nlayout: default\n---\n\n<nav id='sidebar'>\n\t{% include nav.html %}\n</nav>\n\n<section id='content'>\n{% for post in site.posts %}\n  <article class='{{ post.type }}'>\n    <a name='{{ post.url }}' href='#{{ post.url }}'>\n\t\t\t<h2>{% if post.type %}<code><b>{{ post.type }}</b> {{ post.apiurl }}</code> {% endif %}{{ post.title }}</h2></a>\n    <section class='body'>\n      {{ post.content }}\n\t\t\t<div>{% if post.sample_doc %} For more example, see the <a href=doc/{{post.sample_doc}}>{{post.sample_doc}}</a>{% endif %}</div>\n    </section>\n  </article>\n{% endfor %}\n</section>\n"
  },
  {
    "path": "docs/robots.txt",
    "content": "User-agent: *\nDisallow: /images/"
  },
  {
    "path": "g/g.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport \"path/filepath\"\n\nvar Modules map[string]bool\nvar BinOf map[string]string\nvar cfgOf map[string]string\nvar ModuleApps map[string]string\nvar logpathOf map[string]string\nvar PidOf map[string]string\nvar AllModulesInOrder []string\n\nfunc init() {\n\tModules = map[string]bool{\n\t\t\"agent\":      true,\n\t\t\"aggregator\": true,\n\t\t\"graph\":      true,\n\t\t\"hbs\":        true,\n\t\t\"judge\":      true,\n\t\t\"nodata\":     true,\n\t\t\"transfer\":   true,\n\t\t\"gateway\":    true,\n\t\t\"api\":        true,\n\t\t\"alarm\":      true,\n\t\t\"falcon2p8s\": true,\n\t}\n\n\tBinOf = map[string]string{\n\t\t\"agent\":      \"./agent/bin/falcon-agent\",\n\t\t\"aggregator\": \"./aggregator/bin/falcon-aggregator\",\n\t\t\"graph\":      \"./graph/bin/falcon-graph\",\n\t\t\"hbs\":        \"./hbs/bin/falcon-hbs\",\n\t\t\"judge\":      \"./judge/bin/falcon-judge\",\n\t\t\"nodata\":     \"./nodata/bin/falcon-nodata\",\n\t\t\"transfer\":   \"./transfer/bin/falcon-transfer\",\n\t\t\"gateway\":    \"./gateway/bin/falcon-gateway\",\n\t\t\"api\":        \"./api/bin/falcon-api\",\n\t\t\"alarm\":      \"./alarm/bin/falcon-alarm\",\n\t\t\"falcon2p8s\": \"./falcon2p8s/bin/falcon-falcon2p8s\",\n\t}\n\n\tcfgOf = map[string]string{\n\t\t\"agent\":      \"./agent/config/cfg.json\",\n\t\t\"aggregator\": \"./aggregator/config/cfg.json\",\n\t\t\"graph\":      \"./graph/config/cfg.json\",\n\t\t\"hbs\":        \"./hbs/config/cfg.json\",\n\t\t\"judge\":      \"./judge/config/cfg.json\",\n\t\t\"nodata\":     \"./nodata/config/cfg.json\",\n\t\t\"transfer\":   \"./transfer/config/cfg.json\",\n\t\t\"gateway\":    \"./gateway/config/cfg.json\",\n\t\t\"api\":        \"./api/config/cfg.json\",\n\t\t\"alarm\":      \"./alarm/config/cfg.json\",\n\t\t\"falcon2p8s\": \"./falcon2p8s/config/cfg.json\",\n\t}\n\n\tModuleApps = map[string]string{\n\t\t\"agent\":      \"falcon-agent\",\n\t\t\"aggregator\": \"falcon-aggregator\",\n\t\t\"graph\":      \"falcon-graph\",\n\t\t\"hbs\":        \"falcon-hbs\",\n\t\t\"judge\":      \"falcon-judge\",\n\t\t\"nodata\":     \"falcon-nodata\",\n\t\t\"transfer\":   \"falcon-transfer\",\n\t\t\"gateway\":    \"falcon-gateway\",\n\t\t\"api\":        \"falcon-api\",\n\t\t\"alarm\":      \"falcon-alarm\",\n\t\t\"falcon2p8s\": \"falcon-falcon2p8s\",\n\t}\n\n\tlogpathOf = map[string]string{\n\t\t\"agent\":      \"./agent/logs/agent.log\",\n\t\t\"aggregator\": \"./aggregator/logs/aggregator.log\",\n\t\t\"graph\":      \"./graph/logs/graph.log\",\n\t\t\"hbs\":        \"./hbs/logs/hbs.log\",\n\t\t\"judge\":      \"./judge/logs/judge.log\",\n\t\t\"nodata\":     \"./nodata/logs/nodata.log\",\n\t\t\"transfer\":   \"./transfer/logs/transfer.log\",\n\t\t\"gateway\":    \"./gateway/logs/gateway.log\",\n\t\t\"api\":        \"./api/logs/api.log\",\n\t\t\"alarm\":      \"./alarm/logs/alarm.log\",\n\t\t\"falcon2p8s\": \"./falcon2p8s/logs/falcon2p8s.log\",\n\t}\n\n\tPidOf = map[string]string{\n\t\t\"agent\":      \"<NOT SET>\",\n\t\t\"aggregator\": \"<NOT SET>\",\n\t\t\"graph\":      \"<NOT SET>\",\n\t\t\"hbs\":        \"<NOT SET>\",\n\t\t\"judge\":      \"<NOT SET>\",\n\t\t\"nodata\":     \"<NOT SET>\",\n\t\t\"transfer\":   \"<NOT SET>\",\n\t\t\"gateway\":    \"<NOT SET>\",\n\t\t\"api\":        \"<NOT SET>\",\n\t\t\"alarm\":      \"<NOT SET>\",\n\t\t\"falcon2p8s\": \"<NOT SET>\",\n\t}\n\n\t// Modules are deployed in this order\n\tAllModulesInOrder = []string{\n\t\t\"graph\",\n\t\t\"hbs\",\n\t\t\"judge\",\n\t\t\"transfer\",\n\t\t\"nodata\",\n\t\t\"aggregator\",\n\t\t\"agent\",\n\t\t\"gateway\",\n\t\t\"api\",\n\t\t\"alarm\",\n\t\t\"falcon2p8s\",\n\t}\n}\n\nfunc Bin(name string) string {\n\tp, _ := filepath.Abs(BinOf[name])\n\treturn p\n}\n\nfunc Cfg(name string) string {\n\tp, _ := filepath.Abs(cfgOf[name])\n\treturn p\n}\n\nfunc LogPath(name string) string {\n\tp, _ := filepath.Abs(logpathOf[name])\n\treturn p\n}\n\nfunc LogDir(name string) string {\n\td, _ := filepath.Abs(filepath.Dir(logpathOf[name]))\n\treturn d\n}\n"
  },
  {
    "path": "g/tool.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nfunc HasLogfile(name string) bool {\n\tif _, err := os.Stat(LogPath(name)); err != nil {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc PreqOrder(moduleArgs []string) []string {\n\tif len(moduleArgs) == 0 {\n\t\treturn []string{}\n\t}\n\n\tvar modulesInOrder []string\n\n\t// get arguments which are found in the order\n\tfor _, nameOrder := range AllModulesInOrder {\n\t\tfor _, nameArg := range moduleArgs {\n\t\t\tif nameOrder == nameArg {\n\t\t\t\tmodulesInOrder = append(modulesInOrder, nameOrder)\n\t\t\t}\n\t\t}\n\t}\n\t// get arguments which are not found in the order\n\tfor _, nameArg := range moduleArgs {\n\t\tend := 0\n\t\tfor _, nameOrder := range modulesInOrder {\n\t\t\tif nameOrder == nameArg {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tend++\n\t\t}\n\t\tif end == len(modulesInOrder) {\n\t\t\tmodulesInOrder = append(modulesInOrder, nameArg)\n\t\t}\n\t}\n\treturn modulesInOrder\n}\n\nfunc Rel(p string) string {\n\twd, err := os.Getwd()\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\t// filepath.Abs() returns an error only when os.Getwd() returns an error;\n\tabs, _ := filepath.Abs(p)\n\n\tr, err := filepath.Rel(wd, abs)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\treturn r\n}\n\nfunc HasCfg(name string) bool {\n\tif _, err := os.Stat(Cfg(name)); err != nil {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc HasModule(name string) bool {\n\treturn Modules[name]\n}\n\nfunc setPid(name string) {\n\toutput, _ := exec.Command(\"pgrep\", \"-f\", ModuleApps[name]).Output()\n\tpidStr := strings.TrimSpace(string(output))\n\tPidOf[name] = pidStr\n}\n\nfunc Pid(name string) string {\n\tif PidOf[name] == \"<NOT SET>\" {\n\t\tsetPid(name)\n\t}\n\treturn PidOf[name]\n}\n\nfunc IsRunning(name string) bool {\n\tsetPid(name)\n\treturn Pid(name) != \"\"\n}\n\nfunc RmDup(args []string) []string {\n\tif len(args) == 0 {\n\t\treturn []string{}\n\t}\n\tif len(args) == 1 {\n\t\treturn args\n\t}\n\n\tret := []string{}\n\tisDup := make(map[string]bool)\n\tfor _, arg := range args {\n\t\tif isDup[arg] == true {\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, arg)\n\t\tisDup[arg] = true\n\t}\n\treturn ret\n}\n"
  },
  {
    "path": "g/tool_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc setup() {\n\tos.MkdirAll(\"falcon-module/config\", 755)\n\tos.MkdirAll(\"falcon-module-without-cfg/config\", 755)\n\tos.Create(\"falcon-module/config/cfg.json\")\n\tcfgOf = map[string]string{\n\t\t\"falcon-module\":             \"falcon-module/config/cfg.json\",\n\t\t\"falcon-module-without-cfg\": \"falcon-module-without-cfg/config/cfg.json\",\n\t}\n\tModules = map[string]bool{\n\t\t\"falcon-module\":             true,\n\t\t\"falcon-module-without-cfg\": true,\n\t}\n\tAllModulesInOrder = []string{\n\t\t\"1st-module\",\n\t\t\"2nd-module\",\n\t\t\"3rd-module\",\n\t}\n}\n\nfunc teardown() {\n\tos.RemoveAll(\"falcon-module\")\n\tos.RemoveAll(\"falcon-module-without-cfg\")\n}\n\nfunc TestRel(t *testing.T) {\n\twd, err := os.Getwd()\n\tif err != nil {\n\t\tt.Error(err)\n\t\tos.Exit(1)\n\t}\n\ttests := []struct {\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\"falcon-module/config/cfg.json\", \"falcon-module/config/cfg.json\"},\n\t\t{\"./falcon-module/config/cfg.json\", \"falcon-module/config/cfg.json\"},\n\t\t{filepath.Join(wd, \"falcon-module/config/cfg.json\"), \"falcon-module/config/cfg.json\"},\n\t}\n\n\tfor i, v := range tests {\n\t\tactual := Rel(v.input)\n\t\texpected := v.expected\n\t\tt.Logf(\"Check case %d: %s(actual) == %s(expected)\", i, actual, expected)\n\t\tif actual != expected {\n\t\t\tt.Errorf(\"Error on case %d: %s(actual) != %s(expected)\", i, actual, expected)\n\t\t}\n\t}\n}\n\nfunc TestHasCfg(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected bool\n\t}{\n\t\t{\"falcon-module\", true},\n\t\t{\"falcon-module-without-cfg\", false},\n\t}\n\n\tfor i, v := range tests {\n\t\tactual := HasCfg(v.input)\n\t\texpected := v.expected\n\t\tt.Logf(\"Check case %v: %v(actual) == %v(expected)\", i, actual, expected)\n\t\tif !reflect.DeepEqual(actual, expected) {\n\t\t\tt.Errorf(\"Error on case %v: %v(actual) != %v(expected)\", i, actual, expected)\n\t\t}\n\t}\n}\n\nfunc TestPreqOrder(t *testing.T) {\n\ttests := []struct {\n\t\tinput    []string\n\t\texpected []string\n\t}{\n\t\t{[]string{\"2nd-module\", \"1st-module\"}, []string{\"1st-module\", \"2nd-module\"}},\n\t\t{[]string{\"2nd-module\", \"1st-module\", \"3rd-module\"}, []string{\"1st-module\", \"2nd-module\", \"3rd-module\"}},\n\t\t{[]string{\"3rd-module\", \"2nd-module\", \"1st-module\"}, []string{\"1st-module\", \"2nd-module\", \"3rd-module\"}},\n\t\t{[]string{\"3rd-module\", \"other-module\", \"1st-module\", \"2nd-module\"}, []string{\"1st-module\", \"2nd-module\", \"3rd-module\", \"other-module\"}},\n\t\t{[]string{\"other-module\", \"1st-module\", \"2nd-module\", \"3rd-module\"}, []string{\"1st-module\", \"2nd-module\", \"3rd-module\", \"other-module\"}},\n\t}\n\tfor i, v := range tests {\n\t\tactual := PreqOrder(v.input)\n\t\texpected := v.expected\n\t\tt.Logf(\"Check case %d: %s(actual) == %s(expected)\", i, actual, expected)\n\t\tif !reflect.DeepEqual(actual, expected) {\n\t\t\tt.Errorf(\"Error on case %d: %s(actual) != %s(expected)\", i, actual, expected)\n\t\t}\n\t}\n}\n\nfunc TestRmDup(t *testing.T) {\n\ttests := []struct {\n\t\tinput    []string\n\t\texpected []string\n\t}{\n\t\t{[]string{\"2nd-module\", \"1st-module\"}, []string{\"2nd-module\", \"1st-module\"}},\n\t\t{[]string{\"2nd-module\", \"1st-module\", \"1st-module\"}, []string{\"2nd-module\", \"1st-module\"}},\n\t\t{[]string{\"2nd-module\", \"2nd-module\", \"1st-module\"}, []string{\"2nd-module\", \"1st-module\"}},\n\t\t{[]string{\"1st-module\", \"2nd-module\", \"1st-module\"}, []string{\"1st-module\", \"2nd-module\"}},\n\t\t{[]string{\"2nd-module\", \"1st-module\", \"2nd-module\"}, []string{\"2nd-module\", \"1st-module\"}},\n\t\t{[]string{\"2nd-module\", \"2nd-module\", \"1st-module\", \"3rd-module\"}, []string{\"2nd-module\", \"1st-module\", \"3rd-module\"}},\n\t\t{[]string{\"2nd-module\", \"1st-module\", \"1st-module\", \"3rd-module\"}, []string{\"2nd-module\", \"1st-module\", \"3rd-module\"}},\n\t\t{[]string{\"2nd-module\", \"1st-module\", \"3rd-module\", \"3rd-module\"}, []string{\"2nd-module\", \"1st-module\", \"3rd-module\"}},\n\t\t{[]string{\"2nd-module\", \"1st-module\", \"2nd-module\", \"1st-module\", \"3rd-module\"}, []string{\"2nd-module\", \"1st-module\", \"3rd-module\"}},\n\t\t{[]string{\"2nd-module\", \"1st-module\", \"2nd-module\", \"3rd-module\"}, []string{\"2nd-module\", \"1st-module\", \"3rd-module\"}},\n\t\t{[]string{\"2nd-module\", \"1st-module\", \"3rd-module\", \"1st-module\"}, []string{\"2nd-module\", \"1st-module\", \"3rd-module\"}},\n\t}\n\tfor i, v := range tests {\n\t\tactual := RmDup(v.input)\n\t\texpected := v.expected\n\t\tt.Logf(\"Check case %d: %s(actual) == %s(expected)\", i, actual, expected)\n\t\tif !reflect.DeepEqual(actual, expected) {\n\t\t\tt.Errorf(\"Error on case %d: %s(actual) != %s(expected)\", i, actual, expected)\n\t\t}\n\t}\n}\n\nfunc TestMain(m *testing.M) {\n\tsetup()\n\tcode := m.Run()\n\tteardown()\n\tos.Exit(code)\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/open-falcon/falcon-plus\n\ngo 1.15\n\nrequire (\n\tgithub.com/astaxie/beego v1.8.3\n\tgithub.com/denisenkom/go-mssqldb v0.10.0 // indirect\n\tgithub.com/emirpasic/gods v1.9.0\n\tgithub.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect\n\tgithub.com/garyburd/redigo v1.6.2\n\tgithub.com/gin-gonic/gin v1.7.0\n\tgithub.com/go-resty/resty v0.0.0-00010101000000-000000000000 // indirect\n\tgithub.com/go-sql-driver/mysql v1.6.0\n\tgithub.com/golang/protobuf v1.5.2 // indirect\n\tgithub.com/influxdata/influxdb v1.9.0\n\tgithub.com/jinzhu/gorm v0.0.0-20170703134954-2a1463811ee1\n\tgithub.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d // indirect\n\tgithub.com/jinzhu/now v1.1.2 // indirect\n\tgithub.com/json-iterator/go v1.1.11 // indirect\n\tgithub.com/juju/errors v0.0.0-20200330140219-3fe23663418f\n\tgithub.com/juju/testing v0.0.0-20210324180055-18c50b0c2098 // indirect\n\tgithub.com/lib/pq v1.10.2 // indirect\n\tgithub.com/masato25/resty v0.4.2-0.20161209040832-927c0e7d74a0\n\tgithub.com/masato25/yaag v0.0.0-20170704095552-00862ec4db8e\n\tgithub.com/mattn/go-isatty v0.0.13 // indirect\n\tgithub.com/mattn/go-sqlite3 v1.14.7 // indirect\n\tgithub.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989\n\tgithub.com/niean/go-metrics-lite v0.0.0-20151230091537-b5d30971b578 // indirect\n\tgithub.com/niean/goperfcounter v0.0.0-20160108100052-24860a8d3fac\n\tgithub.com/niean/gotools v0.0.0-20151221085310-ff3f51fc5c60 // indirect\n\tgithub.com/oleiade/lane v1.0.1\n\tgithub.com/open-falcon/rrdlite v0.0.0-20170412122036-7d8646c85cc5\n\tgithub.com/prometheus/client_golang v1.5.1\n\tgithub.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b\n\tgithub.com/sirupsen/logrus v1.8.1\n\tgithub.com/smartystreets/goconvey v1.6.4\n\tgithub.com/spf13/cobra v1.1.3\n\tgithub.com/spf13/viper v1.7.0\n\tgithub.com/stretchr/testify v1.6.1 // indirect\n\tgithub.com/toolkits/cache v0.0.0-20190218093630-cfb07b7585e5\n\tgithub.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3\n\tgithub.com/toolkits/conn_pool v0.0.0-20170512061817-2b758bec1177\n\tgithub.com/toolkits/consistent v0.0.0-20150827090850-a6f56a64d1b1\n\tgithub.com/toolkits/container v0.0.0-20151219225805-ba7d73adeaca\n\tgithub.com/toolkits/core v0.0.0-20141116054942-0ebf14900fe2\n\tgithub.com/toolkits/cron v0.0.0-20150624115642-bebc2953afa6\n\tgithub.com/toolkits/file v0.0.0-20160325033739-a5b3c5147e07\n\tgithub.com/toolkits/http v0.0.0-20150609122824-f3ac6e6c24be\n\tgithub.com/toolkits/net v0.0.0-20160910085801-3f39ab6fe3ce\n\tgithub.com/toolkits/nux v0.0.0-20200401110743-debb3829764a\n\tgithub.com/toolkits/proc v0.0.0-20170520054645-8c734d0eb018\n\tgithub.com/toolkits/slice v0.0.0-20141116085117-e44a80af2484\n\tgithub.com/toolkits/str v0.0.0-20160913030958-f82e0f0498cb\n\tgithub.com/toolkits/sys v0.0.0-20170615103026-1f33b217ffaf\n\tgithub.com/toolkits/time v0.0.0-20160524122720-c274716e8d7f\n\tgithub.com/ugorji/go v1.2.6 // indirect\n\tgolang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect\n\tgolang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect\n\tgolang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea // indirect\n\tgopkg.in/go-playground/assert.v1 v1.2.1 // indirect\n\tgopkg.in/go-playground/validator.v8 v8.18.2 // indirect\n\n)\n\nreplace github.com/go-resty/resty => gopkg.in/resty.v1 v1.11.0\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=\ncloud.google.com/go/bigtable v1.3.0/go.mod h1:z5EyKrPE8OQmeg4h5MNdKvuSnI9CCT49Ki3f23aBzio=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncollectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/Azure/azure-sdk-for-go v41.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=\ngithub.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=\ngithub.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=\ngithub.com/Azure/go-autorest/autorest v0.10.0/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=\ngithub.com/Azure/go-autorest/autorest v0.10.1/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=\ngithub.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=\ngithub.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=\ngithub.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=\ngithub.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=\ngithub.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=\ngithub.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=\ngithub.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw=\ngithub.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=\ngithub.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=\ngithub.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=\ngithub.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=\ngithub.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=\ngithub.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=\ngithub.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=\ngithub.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=\ngithub.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=\ngithub.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=\ngithub.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=\ngithub.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=\ngithub.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=\ngithub.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=\ngithub.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=\ngithub.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=\ngithub.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=\ngithub.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=\ngithub.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=\ngithub.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=\ngithub.com/SAP/go-hdb v0.14.1/go.mod h1:7fdQLVC2lER3urZLjZCm0AuMQfApof92n3aylBPEkMo=\ngithub.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=\ngithub.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=\ngithub.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=\ngithub.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=\ngithub.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=\ngithub.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=\ngithub.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=\ngithub.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=\ngithub.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=\ngithub.com/apache/arrow/go/arrow v0.0.0-20200923215132-ac86123a3f01/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0=\ngithub.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=\ngithub.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=\ngithub.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=\ngithub.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=\ngithub.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=\ngithub.com/astaxie/beego v1.8.3 h1:6SwgDPBxYSs+E2cwIL7BzQn4nWgY8xwYE8wO6YpNa9k=\ngithub.com/astaxie/beego v1.8.3/go.mod h1:0R4++1tUqERR0WYFWdfkcrsyoVBCG4DgpDGokT3yb+U=\ngithub.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=\ngithub.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=\ngithub.com/aws/aws-sdk-go v1.29.16/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=\ngithub.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=\ngithub.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=\ngithub.com/benbjohnson/immutable v0.2.1/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=\ngithub.com/benbjohnson/tmpl v1.0.0/go.mod h1:igT620JFIi44B6awvU9IsDhR77IXWtFigTLil/RPdps=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=\ngithub.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=\ngithub.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=\ngithub.com/bonitoo-io/go-sql-bigquery v0.3.4-1.4.0/go.mod h1:J4Y6YJm0qTWB9aFziB7cPeSyc6dOZFyJdteSeybVpXQ=\ngithub.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=\ngithub.com/cactus/go-statsd-client/statsd v0.0.0-20191106001114-12b4e2b38748/go.mod h1:l/bIBLeOl9eX+wxJAzxS4TveKRtAqlyDpHjhkfO0MEI=\ngithub.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=\ngithub.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=\ngithub.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=\ngithub.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=\ngithub.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=\ngithub.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=\ngithub.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=\ngithub.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=\ngithub.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=\ngithub.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=\ngithub.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8=\ngithub.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=\ngithub.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=\ngithub.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=\ngithub.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=\ngithub.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=\ngithub.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=\ngithub.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=\ngithub.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=\ngithub.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=\ngithub.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=\ngithub.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=\ngithub.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=\ngithub.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=\ngithub.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=\ngithub.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=\ngithub.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=\ngithub.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=\ngithub.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=\ngithub.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo=\ngithub.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=\ngithub.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=\ngithub.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=\ngithub.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=\ngithub.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=\ngithub.com/foxcpp/go-mockdns v0.0.0-20201212160233-ede2f9158d15/go.mod h1:tPg4cp4nseejPd+UKxtCVQ2hUxNTZ7qQZJa7CLriIeo=\ngithub.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=\ngithub.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=\ngithub.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM=\ngithub.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=\ngithub.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=\ngithub.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=\ngithub.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=\ngithub.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=\ngithub.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=\ngithub.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=\ngithub.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU=\ngithub.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=\ngithub.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=\ngithub.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=\ngithub.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=\ngithub.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=\ngithub.com/go-chi/chi v4.1.0+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=\ngithub.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=\ngithub.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=\ngithub.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=\ngithub.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=\ngithub.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=\ngithub.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=\ngithub.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ=\ngithub.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=\ngithub.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=\ngithub.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=\ngithub.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=\ngithub.com/go-openapi/errors v0.19.4/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=\ngithub.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=\ngithub.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=\ngithub.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=\ngithub.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=\ngithub.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=\ngithub.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=\ngithub.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=\ngithub.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=\ngithub.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=\ngithub.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=\ngithub.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=\ngithub.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=\ngithub.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=\ngithub.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=\ngithub.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI=\ngithub.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=\ngithub.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY=\ngithub.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=\ngithub.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=\ngithub.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=\ngithub.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo=\ngithub.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=\ngithub.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=\ngithub.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=\ngithub.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=\ngithub.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=\ngithub.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=\ngithub.com/go-openapi/spec v0.19.7/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=\ngithub.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=\ngithub.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=\ngithub.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=\ngithub.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=\ngithub.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=\ngithub.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=\ngithub.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=\ngithub.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=\ngithub.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=\ngithub.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=\ngithub.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=\ngithub.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=\ngithub.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=\ngithub.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=\ngithub.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=\ngithub.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=\ngithub.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo=\ngithub.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=\ngithub.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=\ngithub.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=\ngithub.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=\ngithub.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=\ngithub.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=\ngithub.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=\ngithub.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=\ngithub.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=\ngithub.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=\ngithub.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=\ngithub.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=\ngithub.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=\ngithub.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=\ngithub.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=\ngithub.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=\ngithub.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=\ngithub.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=\ngithub.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=\ngithub.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=\ngithub.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=\ngithub.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=\ngithub.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=\ngithub.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=\ngithub.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=\ngithub.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=\ngithub.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=\ngithub.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=\ngithub.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=\ngithub.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=\ngithub.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=\ngithub.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=\ngithub.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=\ngithub.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=\ngithub.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=\ngithub.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=\ngithub.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=\ngithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=\ngithub.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200417002340-c6e0a841f49a/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=\ngithub.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=\ngithub.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=\ngithub.com/gophercloud/gophercloud v0.10.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=\ngithub.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=\ngithub.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=\ngithub.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=\ngithub.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=\ngithub.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=\ngithub.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=\ngithub.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=\ngithub.com/grpc-ecosystem/grpc-gateway v1.14.4/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=\ngithub.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=\ngithub.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=\ngithub.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU=\ngithub.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=\ngithub.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=\ngithub.com/hashicorp/consul/sdk v0.4.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=\ngithub.com/hashicorp/go-hclog v0.12.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=\ngithub.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=\ngithub.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=\ngithub.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=\ngithub.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=\ngithub.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=\ngithub.com/hashicorp/memberlist v0.2.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=\ngithub.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=\ngithub.com/hashicorp/serf v0.9.0/go.mod h1:YL0HO+FifKOW2u1ke99DGVu1zhcpZzNwrLIqBC7vbYU=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=\ngithub.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=\ngithub.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=\ngithub.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/influxdata/flux v0.65.0/go.mod h1:BwN2XG2lMszOoquQaFdPET8FRQfrXiZsWmcMO9rkaVY=\ngithub.com/influxdata/flux v0.113.0/go.mod h1:3TJtvbm/Kwuo5/PEo5P6HUzwVg4bXWkb2wPQHPtQdlU=\ngithub.com/influxdata/httprouter v1.3.1-0.20191122104820-ee83e2772f69/go.mod h1:pwymjR6SrP3gD3pRj9RJwdl1j5s3doEEV8gS4X9qSzA=\ngithub.com/influxdata/influxdb v1.8.0/go.mod h1:SIzcnsjaHRFpmlxpJ4S3NT64qtEKYweNTUMb/vh0OMQ=\ngithub.com/influxdata/influxdb v1.9.0 h1:9z/aRmTpWT1rIm4EN+qTJTZqgEdLGZ4xRMgvA276UEA=\ngithub.com/influxdata/influxdb v1.9.0/go.mod h1:UEe3MeD9AaP5rlPIes102IhYua3FhIWZuOXNHxDjSrI=\ngithub.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=\ngithub.com/influxdata/influxql v1.1.0/go.mod h1:KpVI7okXjK6PRi3Z5B+mtKZli+R1DnZgb3N+tzevNgo=\ngithub.com/influxdata/influxql v1.1.1-0.20210223160523-b6ab99450c93/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk=\ngithub.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE=\ngithub.com/influxdata/pkg-config v0.2.6/go.mod h1:EMS7Ll0S4qkzDk53XS3Z72/egBsPInt+BeRxb0WeSwk=\ngithub.com/influxdata/pkg-config v0.2.7/go.mod h1:EMS7Ll0S4qkzDk53XS3Z72/egBsPInt+BeRxb0WeSwk=\ngithub.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8=\ngithub.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=\ngithub.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=\ngithub.com/influxdata/tdigest v0.0.2-0.20210216194612-fc98d27c9e8b/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y=\ngithub.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jinzhu/gorm v0.0.0-20170703134954-2a1463811ee1 h1:sWeCm69jE8uwB/gHLNG65Szf24KebYqoWq1boLccYcQ=\ngithub.com/jinzhu/gorm v0.0.0-20170703134954-2a1463811ee1/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=\ngithub.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d h1:jRQLvyVGL+iVtDElaEIDdKwpPqUIZJfzkNLV34htpEc=\ngithub.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=\ngithub.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=\ngithub.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=\ngithub.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=\ngithub.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=\ngithub.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=\ngithub.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=\ngithub.com/jsternberg/zap-logfmt v1.2.0/go.mod h1:kz+1CUmCutPWABnNkOu9hOHKdT2q3TDYCcsFy9hpqb0=\ngithub.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/juju/ansiterm v0.0.0-20160907234532-b99631de12cf/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=\ngithub.com/juju/clock v0.0.0-20190205081909-9c5c9712527c/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=\ngithub.com/juju/cmd v0.0.0-20171107070456-e74f39857ca0/go.mod h1:yWJQHl73rdSX4DHVKGqkAip+huBslxRwS8m9CrOLq18=\ngithub.com/juju/collections v0.0.0-20200605021417-0d0ec82b7271/go.mod h1:5XgO71dV1JClcOJE+4dzdn4HrI5LiyKd7PlVG6eZYhY=\ngithub.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=\ngithub.com/juju/errors v0.0.0-20200330140219-3fe23663418f h1:MCOvExGLpaSIzLYB4iQXEHP4jYVU6vmzLNQPdMVrxnM=\ngithub.com/juju/errors v0.0.0-20200330140219-3fe23663418f/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=\ngithub.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=\ngithub.com/juju/httpprof v0.0.0-20141217160036-14bf14c30767/go.mod h1:+MaLYz4PumRkkyHYeXJ2G5g5cIW0sli2bOfpmbaMV/g=\ngithub.com/juju/loggo v0.0.0-20170605014607-8232ab8918d9/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=\ngithub.com/juju/loggo v0.0.0-20200526014432-9ce3a2e09b5e h1:FdDd7bdI6cjq5vaoYlK1mfQYfF9sF2VZw8VEZMsl5t8=\ngithub.com/juju/loggo v0.0.0-20200526014432-9ce3a2e09b5e/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=\ngithub.com/juju/mgo/v2 v2.0.0-20210302023703-70d5d206e208 h1:/WiCm+Vpj87e4QWuWwPD/bNE9kDrWCLvPBHOQNcG2+A=\ngithub.com/juju/mgo/v2 v2.0.0-20210302023703-70d5d206e208/go.mod h1:0OChplkvPTZ174D2FYZXg4IB9hbEwyHkD+zT+/eK+Fg=\ngithub.com/juju/mutex v0.0.0-20171110020013-1fe2a4bf0a3a/go.mod h1:Y3oOzHH8CQ0Ppt0oCKJ2JFO81/EsWenH5AEqigLH+yY=\ngithub.com/juju/retry v0.0.0-20151029024821-62c620325291/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4=\ngithub.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4=\ngithub.com/juju/testing v0.0.0-20180402130637-44801989f0f7/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=\ngithub.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=\ngithub.com/juju/testing v0.0.0-20210324180055-18c50b0c2098 h1:yrhek184cGp0IRyHg0uV1khLaorNg6GtDLkry4oNNjE=\ngithub.com/juju/testing v0.0.0-20210324180055-18c50b0c2098/go.mod h1:7lxZW0B50+xdGFkvhAb8bwAGt6IU87JB1H9w4t8MNVM=\ngithub.com/juju/utils v0.0.0-20180424094159-2000ea4ff043/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk=\ngithub.com/juju/utils v0.0.0-20200116185830-d40c2fe10647/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk=\ngithub.com/juju/utils/v2 v2.0.0-20200923005554-4646bfea2ef1/go.mod h1:fdlDtQlzundleLLz/ggoYinEt/LmnrpNKcNTABQATNI=\ngithub.com/juju/version v0.0.0-20161031051906-1f41e27e54f2/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=\ngithub.com/juju/version v0.0.0-20180108022336-b64dbd566305/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=\ngithub.com/juju/version v0.0.0-20191219164919-81c1be00b9a6/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=\ngithub.com/julienschmidt/httprouter v1.1.1-0.20151013225520-77a895ad01eb/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=\ngithub.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=\ngithub.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=\ngithub.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=\ngithub.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=\ngithub.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=\ngithub.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=\ngithub.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=\ngithub.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=\ngithub.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=\ngithub.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=\ngithub.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\ngithub.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=\ngithub.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=\ngithub.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=\ngithub.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=\ngithub.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=\ngithub.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=\ngithub.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=\ngithub.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=\ngithub.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=\ngithub.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=\ngithub.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=\ngithub.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=\ngithub.com/masato25/resty v0.4.2-0.20161209040832-927c0e7d74a0 h1:N7lnRiOJGYBnyKNeAJPASQh1zIEAXpE82K4tZdk7CEU=\ngithub.com/masato25/resty v0.4.2-0.20161209040832-927c0e7d74a0/go.mod h1:/lGdnJcqS5VKHZIVQZifCge9J8eFdVNFt6VYwjZdedo=\ngithub.com/masato25/yaag v0.0.0-20170704095552-00862ec4db8e h1:55FVIPgrRTPWYz+mUa7m6lo5s8z2Y/OPj+EHEC5jx8Q=\ngithub.com/masato25/yaag v0.0.0-20170704095552-00862ec4db8e/go.mod h1:V4fa2eVm9p80MCLIl5kv5Aw6Uc0pRL2dYSV4lNK+2PU=\ngithub.com/masterzen/azure-sdk-for-go v3.2.0-beta.0.20161014135628-ee4f0065d00c+incompatible/go.mod h1:mf8fjOu33zCqxUjuiU3I8S1lJMyEAlH+0F2+M5xl3hE=\ngithub.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc=\ngithub.com/masterzen/winrm v0.0.0-20161014151040-7a535cd943fc/go.mod h1:CfZSN7zwz5gJiFhZJz49Uzk7mEBHIceWmbFmYx7Hf7E=\ngithub.com/masterzen/xmlpath v0.0.0-20140218185901-13f4951698ad/go.mod h1:A0zPC53iKKKcXYxr4ROjpQRQ5FgJXtelNdSmHHuq/tY=\ngithub.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=\ngithub.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=\ngithub.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=\ngithub.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=\ngithub.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=\ngithub.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=\ngithub.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=\ngithub.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=\ngithub.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=\ngithub.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=\ngithub.com/mileusna/useragent v0.0.0-20190129205925-3e331f0949a5/go.mod h1:JWhYAp2EXqUtsxTKdeGlY8Wp44M7VxThC9FEoNGi2IE=\ngithub.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989 h1:PS1dLCGtD8bb9RPKJrc8bS7qHL6JnW1CZvwzH9dPoUs=\ngithub.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY=\ngithub.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=\ngithub.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=\ngithub.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=\ngithub.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=\ngithub.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=\ngithub.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=\ngithub.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=\ngithub.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=\ngithub.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=\ngithub.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=\ngithub.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=\ngithub.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=\ngithub.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=\ngithub.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=\ngithub.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=\ngithub.com/niean/go-metrics-lite v0.0.0-20151230091537-b5d30971b578 h1:bHDlu3H/z3ITiCCLjAro7dSZTlKy62ZbWHEN5JT7z9M=\ngithub.com/niean/go-metrics-lite v0.0.0-20151230091537-b5d30971b578/go.mod h1:F5oJZruubjYvF/hsrhP/QtVabIKrth79mug76XbqqGU=\ngithub.com/niean/goperfcounter v0.0.0-20160108100052-24860a8d3fac h1:n7YlHLG7nMXh9CdbINXe/39/9eHPU6pEa2pW3QJUSsM=\ngithub.com/niean/goperfcounter v0.0.0-20160108100052-24860a8d3fac/go.mod h1:BIoAJicLFAP0B1TYNsa8nV5Yur3JxpRCdVNC+45yCZI=\ngithub.com/niean/gotools v0.0.0-20151221085310-ff3f51fc5c60 h1:8kcIWCY09RdXZcXUKOWtvjvKTr5Lziq4R/6saxUOhvQ=\ngithub.com/niean/gotools v0.0.0-20151221085310-ff3f51fc5c60/go.mod h1:gH2bvE9/eX49hWK7CwwL/+/y+dodduyxs5cTpBzF5v0=\ngithub.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=\ngithub.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=\ngithub.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=\ngithub.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=\ngithub.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=\ngithub.com/oleiade/lane v1.0.1 h1:hXofkn7GEOubzTwNpeL9MaNy8WxolCYb9cInAIeqShU=\ngithub.com/oleiade/lane v1.0.1/go.mod h1:IyTkraa4maLfjq/GmHR+Dxb4kCMtEGeb+qmhlrQ5Mk4=\ngithub.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=\ngithub.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=\ngithub.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=\ngithub.com/open-falcon/rrdlite v0.0.0-20170412122036-7d8646c85cc5 h1:OZRdjmzU7Q4cuzN4lx7d6zP6L8+Q2dqFfq95CqGcReM=\ngithub.com/open-falcon/rrdlite v0.0.0-20170412122036-7d8646c85cc5/go.mod h1:pXROoG0iWVnqq4u2Ii97S0Vt9iCTVypshsl9HXsV6cs=\ngithub.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=\ngithub.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w=\ngithub.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=\ngithub.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=\ngithub.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=\ngithub.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=\ngithub.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=\ngithub.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=\ngithub.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=\ngithub.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\ngithub.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=\ngithub.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=\ngithub.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=\ngithub.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=\ngithub.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=\ngithub.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=\ngithub.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=\ngithub.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=\ngithub.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=\ngithub.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=\ngithub.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=\ngithub.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=\ngithub.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=\ngithub.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=\ngithub.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=\ngithub.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/prometheus v0.0.0-20200609090129-a6600f564e3c/go.mod h1:S5n0C6tSgdnwWshBUceRx5G1OsjLv/EeZ9t3wIfEtsY=\ngithub.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=\ngithub.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=\ngithub.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=\ngithub.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=\ngithub.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=\ngithub.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=\ngithub.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=\ngithub.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=\ngithub.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=\ngithub.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=\ngithub.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/snowflakedb/gosnowflake v1.3.4/go.mod h1:NsRq2QeiMUuoNUJhp5Q6xGC4uBrsS9g6LwZVEkTWgsE=\ngithub.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=\ngithub.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=\ngithub.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=\ngithub.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=\ngithub.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=\ngithub.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=\ngithub.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=\ngithub.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=\ngithub.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=\ngithub.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=\ngithub.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=\ngithub.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=\ngithub.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=\ngithub.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=\ngithub.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=\ngithub.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=\ngithub.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=\ngithub.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=\ngithub.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=\ngithub.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=\ngithub.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=\ngithub.com/toolkits/cache v0.0.0-20190218093630-cfb07b7585e5 h1:aWeunbUwH8/P2E918Ge885/4wQBgjvkgUkmUGoyrUWQ=\ngithub.com/toolkits/cache v0.0.0-20190218093630-cfb07b7585e5/go.mod h1:NQTo1ikAmZPMbWwBZuRRT6ZR/7fIQJ3MVwe2Hyd/Gg8=\ngithub.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 h1:kF/7m/ZU+0D4Jj5eZ41Zm3IH/J8OElK1Qtd7tVKAwLk=\ngithub.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE=\ngithub.com/toolkits/conn_pool v0.0.0-20170512061817-2b758bec1177 h1:maG51qtOSBRRgQorIBMLgklBZar3mEArIfRuUykjOXo=\ngithub.com/toolkits/conn_pool v0.0.0-20170512061817-2b758bec1177/go.mod h1:t11yckvHOPOwLPIqkILsCakC941LRZ5JqvXayfM37As=\ngithub.com/toolkits/consistent v0.0.0-20150827090850-a6f56a64d1b1 h1:KKVW3VjyAvOcaAtlssIfMRhGDnqQ90VcXGZfaaNvm1M=\ngithub.com/toolkits/consistent v0.0.0-20150827090850-a6f56a64d1b1/go.mod h1:/Oysd5WDkGyGtCOpVwF3OI3Bd4ZzfGgMvGyAf82R1kU=\ngithub.com/toolkits/container v0.0.0-20151219225805-ba7d73adeaca h1:bUNxqD2ULaaoBA5RLX6YJThj2c75S1BUMT4BmzqkE40=\ngithub.com/toolkits/container v0.0.0-20151219225805-ba7d73adeaca/go.mod h1:Z1hsEp8J9dDg5gRss4uixVSS19XDA4dw6S9ZcBm+hB8=\ngithub.com/toolkits/core v0.0.0-20141116054942-0ebf14900fe2 h1:KqJEPqqAyr7+GzVX3JrRkpruhcMTZJF5kEGO93Rfrqo=\ngithub.com/toolkits/core v0.0.0-20141116054942-0ebf14900fe2/go.mod h1:g5CfkC3ciO92SomFWVazgaQM+sUUG19GQrBNNzGwxZk=\ngithub.com/toolkits/cron v0.0.0-20150624115642-bebc2953afa6 h1:+AZ8/esXng2Jj/uG1lxI4Q7eloNovd542ZaB6V4iBIU=\ngithub.com/toolkits/cron v0.0.0-20150624115642-bebc2953afa6/go.mod h1:pp3NVdN4QF/u8CgBrjmLuNkDyX2AMR+fxAx+8M4761I=\ngithub.com/toolkits/file v0.0.0-20160325033739-a5b3c5147e07 h1:d/VUIMNTk65Xz69htmRPNfjypq2uNRqVsymcXQu6kKk=\ngithub.com/toolkits/file v0.0.0-20160325033739-a5b3c5147e07/go.mod h1:FbXpUxsx5in7z/OrWFDdhYetOy3/VGIJsVHN9G7RUPA=\ngithub.com/toolkits/http v0.0.0-20150609122824-f3ac6e6c24be h1:ApRE63RTLWH1wUnnMjzaONcBUQUPNfwIRx8BCDRRY4Q=\ngithub.com/toolkits/http v0.0.0-20150609122824-f3ac6e6c24be/go.mod h1:bsnr8hNMOaKLGhz/elAgwx8ncK3kaH/9NHTzqGQK9Zg=\ngithub.com/toolkits/net v0.0.0-20160910085801-3f39ab6fe3ce h1:XrGffRW+HbN/I45pd25GK3z419YAlHrgTljrQt/ogxk=\ngithub.com/toolkits/net v0.0.0-20160910085801-3f39ab6fe3ce/go.mod h1:6zuR3YGQf7EoHAyqA7EayVehUiQm1ZdGJ2PslJ9Xgls=\ngithub.com/toolkits/nux v0.0.0-20200401110743-debb3829764a h1:tZ18kQ73hny2GuMFDP38LIq0KFAF3hLBqc3kpjAyVlE=\ngithub.com/toolkits/nux v0.0.0-20200401110743-debb3829764a/go.mod h1:YO6BC09QPN1xharvGj2ZKH3uFILpBkrOWKxEgLYfqoo=\ngithub.com/toolkits/proc v0.0.0-20170520054645-8c734d0eb018 h1:3XcjQU/SBh80DXhAZOekQMb287zmYwIyaBlWIo8MhA8=\ngithub.com/toolkits/proc v0.0.0-20170520054645-8c734d0eb018/go.mod h1:qUAga2ZoGIcH8+lJeKAutG8SJry/D4+dQCKnmGbqk9s=\ngithub.com/toolkits/slice v0.0.0-20141116085117-e44a80af2484 h1:ERmNDajjCusGqV3uLhlHhRNpvQiGM1S6pd0RSe3LP+w=\ngithub.com/toolkits/slice v0.0.0-20141116085117-e44a80af2484/go.mod h1:2ZKxkgYEh//pN54EFSkJBak63sg0LxQQFjQmpEwxQx0=\ngithub.com/toolkits/str v0.0.0-20160913030958-f82e0f0498cb h1:K5v44sWq0aO/bgbrH7Ui81wqxZ3pikW4UcIh3UVKOP8=\ngithub.com/toolkits/str v0.0.0-20160913030958-f82e0f0498cb/go.mod h1:j1LqCeE5sJswcBT5LbyTBlZDZHOZ8T9cSxGmTpRvv2E=\ngithub.com/toolkits/sys v0.0.0-20170615103026-1f33b217ffaf h1:1/LnhAvvotcSWDl1ntwUePzLXcyHjAzZ0Ih0F+kKGZU=\ngithub.com/toolkits/sys v0.0.0-20170615103026-1f33b217ffaf/go.mod h1:GejnAYmB2Pr/2fWKp7OGdd6MzuXvRwClmdQAnvnr++I=\ngithub.com/toolkits/time v0.0.0-20160524122720-c274716e8d7f h1:dcluAE5OGvcWy7xfrNrYXQrgEUSK34vBpq7mKTE1zz0=\ngithub.com/toolkits/time v0.0.0-20160524122720-c274716e8d7f/go.mod h1:XaIcQHoNgaZn0rTaVOUwOBrsENnHREEBzWmon3ZjUFY=\ngithub.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=\ngithub.com/uber-go/tally v3.3.15+incompatible/go.mod h1:YDTIBxdXyOU/sCWilKB4bgyufu1cEi0jdVnRdxvjnmU=\ngithub.com/uber/athenadriver v1.1.4/go.mod h1:tQjho4NzXw55LGfSZEcETuYydpY1vtmixUabHkC1K/E=\ngithub.com/uber/jaeger-client-go v2.23.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=\ngithub.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=\ngithub.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=\ngithub.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=\ngithub.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=\ngithub.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=\ngithub.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=\ngithub.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=\ngithub.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=\ngithub.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=\ngithub.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=\ngithub.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=\ngithub.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=\ngithub.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=\ngithub.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=\ngithub.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=\ngithub.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=\ngithub.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngo.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=\ngo.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=\ngo.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=\ngo.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=\ngo.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=\ngo.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=\ngo.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=\ngo.mongodb.org/mongo-driver v1.3.2/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=\ngo.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=\ngo.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=\ngo.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=\ngo.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=\ngo.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=\ngo.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=\ngo.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=\ngo.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=\ngolang.org/x/crypto v0.0.0-20180214000028-650f4a345ab4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20180505025534-4ec37c66abab/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200422194213-44a606286825/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=\ngolang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=\ngolang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180406214816-61147c48b25b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo=\ngolang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea h1:+WiDlPBBaO+h9vPNZi8uJ3k4BkKQB7Iow3aqwHVA5hI=\ngolang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191203134012-c197fd4bf371/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304024140-c4206d458c3f/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200422205258-72e4a01eba43/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200721032237-77f530d86f9a/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=\ngonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=\ngonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=\ngonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=\ngonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=\ngonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=\ngoogle.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=\ngoogle.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200420144010-e5e8543f8aeb/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=\ngopkg.in/errgo.v1 v1.0.0-20161222125816-442357a80af5/go.mod h1:u0ALmqvLRxLI95fkdCEWrE6mhWYZW1aMOJHp5YXLHTg=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=\ngopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=\ngopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=\ngopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=\ngopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=\ngopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=\ngopkg.in/httprequest.v1 v1.1.1/go.mod h1:/CkavNL+g3qLOrpFHVrEx4NKepeqR4XTZWNj4sGGjz0=\ngopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=\ngopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=\ngopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=\ngopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=\ngopkg.in/resty.v1 v1.11.0 h1:z5nqGs/W/h91PLOc+WZefPj8rRZe8Ctlgxg/AtbJ+NE=\ngopkg.in/resty.v1 v1.11.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=\ngopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI=\ngopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=\ngopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=\ngopkg.in/yaml.v2 v2.0.0-20170712054546-1be3d31502d6/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=\ngopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nk8s.io/api v0.17.5/go.mod h1:0zV5/ungglgy2Rlm3QK8fbxkXVs+BSJWpJP/+8gUVLY=\nk8s.io/apimachinery v0.17.5/go.mod h1:ioIo1G/a+uONV7Tv+ZmCbMG1/a3kVw5YcDdncd8ugQ0=\nk8s.io/client-go v0.17.5/go.mod h1:S8uZpBpjJJdEH/fEyxcqg7Rn0P5jH+ilkgBHjriSmNo=\nk8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=\nk8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=\nk8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=\nk8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=\nk8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=\nk8s.io/kube-openapi v0.0.0-20200316234421-82d701f24f9d/go.mod h1:F+5wygcW0wmRTnM3cOgIqGivxkwSWIWT5YdsDbeAOaU=\nk8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=\nk8s.io/utils v0.0.0-20200414100711-2df71ebbae66/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=\nlaunchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=\nlaunchpad.net/xmlpath v0.0.0-20130614043138-000000000004/go.mod h1:vqyExLOM3qBx7mvYRkoxjSCF945s0mbe7YynlKYXtsA=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\nsigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE=\nsigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=\nsourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=\n"
  },
  {
    "path": "main.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/open-falcon/falcon-plus/cmd\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar versionFlag bool\n\nvar RootCmd = &cobra.Command{\n\tUse: \"open-falcon\",\n\tRunE: func(c *cobra.Command, args []string) error {\n\t\tif versionFlag {\n\t\t\tfmt.Printf(\"%s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\t\treturn nil\n\t\t}\n\t\treturn c.Usage()\n\t},\n}\n\nfunc init() {\n\tRootCmd.AddCommand(cmd.Start)\n\tRootCmd.AddCommand(cmd.Stop)\n\tRootCmd.AddCommand(cmd.Restart)\n\tRootCmd.AddCommand(cmd.Check)\n\tRootCmd.AddCommand(cmd.Monitor)\n\tRootCmd.AddCommand(cmd.Reload)\n\n\tRootCmd.Flags().BoolVarP(&versionFlag, \"version\", \"v\", false, \"show version\")\n\tcmd.Start.Flags().BoolVar(&cmd.PreqOrderFlag, \"preq-order\", false, \"start modules in the order of prerequisites\")\n\tcmd.Start.Flags().BoolVar(&cmd.ConsoleOutputFlag, \"console-output\", false, \"print the module's output to the console\")\n}\n\nfunc main() {\n\tif err := RootCmd.Execute(); err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "modules/agent/.gitignore",
    "content": "*.swp\n*.swo\n/cfg.json\n/agent\n/var\n/falcon-agent*\n/falcon_agent\n.DS_Store\n*.iml\n*.idea\n/gitversion\n\n"
  },
  {
    "path": "modules/agent/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "modules/agent/NOTICE",
    "content": "Open-Falcon\n\nCopyright (c) 2014-2015 Xiaomi, Inc. All Rights Reserved.\n\nThis product is licensed to you under the Apache License, Version 2.0 (the \"License\").\nYou may not use this product except in compliance with the License.\n\nThis product may include a number of subcomponents with separate copyright notices\nand license terms. Your use of these subcomponents is subject to the terms and\nconditions of the subcomponent's license, as noted in the LICENSE file.\n"
  },
  {
    "path": "modules/agent/README.md",
    "content": "falcon-agent\n===\n\nThis is a linux monitor agent. Just like zabbix-agent and tcollector.\n\n\n## Installation\n\nIt is a golang classic project\n\n```bash\n# set $GOPATH and $GOROOT\nmkdir -p $GOPATH/src/github.com/open-falcon\ncd $GOPATH/src/github.com/open-falcon\ngit clone https://github.com/open-falcon/falcon-plus.git\ncd falcon-plus/modules/agent\ngo get\n./control build\n./control start\n\n# goto http://localhost:1988\n```\n\nI use [linux-dash](https://github.com/afaqurk/linux-dash) as the page theme.\n\n## Configuration\n\n- heartbeat: heartbeat server rpc address\n- transfer: transfer rpc address\n- ignore: the metrics should ignore\n\n# Auto deployment\n\nJust look at https://github.com/open-falcon/ops-updater\n"
  },
  {
    "path": "modules/agent/cfg.example.json",
    "content": "{\n    \"debug\": true,\n    \"hostname\": \"\",\n    \"ip\": \"\",\n    \"plugin\": {\n        \"enabled\": false,\n        \"dir\": \"./plugin\",\n        \"git\": \"https://github.com/open-falcon/plugin.git\",\n        \"logs\": \"./logs\"\n    },\n    \"heartbeat\": {\n        \"enabled\": true,\n        \"addr\": \"127.0.0.1:6030\",\n        \"interval\": 60,\n        \"timeout\": 1000\n    },\n    \"transfer\": {\n        \"enabled\": true,\n        \"addrs\": [\n            \"127.0.0.1:8433\",\n            \"127.0.0.1:8433\"\n        ],\n        \"interval\": 60,\n        \"timeout\": 1000\n    },\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \":1988\",\n        \"backdoor\": false\n    },\n    \"collector\": {\n        \"ifacePrefix\": [\"eth\", \"em\", \"ens\"],\n        \"mountPoint\": []\n    },\n    \"default_tags\": {\n    },\n    \"ignore\": {\n        \"cpu.busy\": true,\n        \"df.bytes.free\": true,\n        \"df.bytes.total\": true,\n        \"df.bytes.used\": true,\n        \"df.bytes.used.percent\": true,\n        \"df.inodes.total\": true,\n        \"df.inodes.free\": true,\n        \"df.inodes.used\": true,\n        \"df.inodes.used.percent\": true,\n        \"mem.memtotal\": true,\n        \"mem.memused\": true,\n        \"mem.memused.percent\": true,\n        \"mem.memfree\": true,\n        \"mem.swaptotal\": true,\n        \"mem.swapused\": true,\n        \"mem.swapfree\": true\n    }\n}\n"
  },
  {
    "path": "modules/agent/control",
    "content": "#!/bin/bash\n\nWORKSPACE=$(cd $(dirname $0)/; pwd)\ncd $WORKSPACE\n\nmkdir -p var\n\nmodule=agent\napp=falcon-$module\nconf=cfg.json\npidfile=var/app.pid\nlogfile=var/app.log\n\nfunction check_pid() {\n    if [ -f $pidfile ];then\n        pid=`cat $pidfile`\n        if [ -n $pid ]; then\n            running=`ps -p $pid|grep -v \"PID TTY\" |wc -l`\n            return $running\n        fi\n    fi\n    return 0\n}\n\nfunction start() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running already, pid=\"\n        cat $pidfile\n        return 1\n    fi\n\n    if ! [ -f $conf ];then\n        echo \"Config file $conf doesn't exist, creating one.\"\n        cp cfg.example.json $conf\n    fi\n    nohup ./$app -c $conf &> $logfile &\n    sleep 1\n    running=`ps -p $! | grep -v \"PID TTY\" | wc -l`\n    if [ $running -gt 0 ];then\n        echo $! > $pidfile\n        echo \"$app started..., pid=$!\"\n    else\n        echo \"$app failed to start.\"\n        return 1\n    fi\n}\n\nfunction stop() {\n    pid=`cat $pidfile`\n    kill $pid\n    rm -f $pidfile\n    echo \"$app stopped...\"\n}\n\nfunction restart() {\n    stop\n    sleep 1\n    start\n}\n\nfunction status() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo started\n    else\n        echo stopped\n    fi\n}\n\nfunction tailf() {\n    tail -f $logfile\n}\n\nfunction build() {\n    go build\n    if [ $? -ne 0 ]; then\n        exit $?\n    fi\n    mv $module $app\n    ./$app -v\n}\n\nfunction pack() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    file_list=\"public control cfg.example.json $app\"\n    echo \"...tar $app-$version.tar.gz <= $file_list\"\n    tar zcf $app-$version.tar.gz gitversion $file_list\n}\n\nfunction packbin() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-bin-$version.tar.gz $app gitversion\n}\n\nfunction help() {\n    echo \"$0 build|pack|start|stop|restart|status|tail\"\n}\n\nif [ \"$1\" == \"\" ]; then\n    help\nelif [ \"$1\" == \"stop\" ];then\n    stop\nelif [ \"$1\" == \"start\" ];then\n    start\nelif [ \"$1\" == \"restart\" ];then\n    restart\nelif [ \"$1\" == \"status\" ];then\n    status\nelif [ \"$1\" == \"tail\" ];then\n    tailf\nelif [ \"$1\" == \"build\" ];then\n    build\nelif [ \"$1\" == \"pack\" ];then\n    pack\nelif [ \"$1\" == \"packbin\" ];then\n    packbin\nelse\n    help\nfi\n"
  },
  {
    "path": "modules/agent/cron/builtin.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc SyncBuiltinMetrics() {\n\tif g.Config().Heartbeat.Enabled && g.Config().Heartbeat.Addr != \"\" {\n\t\tgo syncBuiltinMetrics()\n\t}\n}\n\nfunc syncBuiltinMetrics() {\n\n\tvar timestamp int64 = -1\n\tvar checksum string = \"nil\"\n\n\tduration := time.Duration(g.Config().Heartbeat.Interval) * time.Second\n\n\tfor {\n\t\ttime.Sleep(duration)\n\n\t\tvar ports = []int64{}\n\t\tvar paths = []string{}\n\t\tvar procs = make(map[string]map[int]string)\n\t\tvar urls = make(map[string]string)\n\n\t\thostname, err := g.Hostname()\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\treq := model.AgentHeartbeatRequest{\n\t\t\tHostname: hostname,\n\t\t\tChecksum: checksum,\n\t\t}\n\n\t\tvar resp model.BuiltinMetricResponse\n\t\terr = g.HbsClient.Call(\"Agent.BuiltinMetrics\", req, &resp)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif resp.Timestamp <= timestamp {\n\t\t\tcontinue\n\t\t}\n\n\t\tif resp.Checksum == checksum {\n\t\t\tcontinue\n\t\t}\n\n\t\ttimestamp = resp.Timestamp\n\t\tchecksum = resp.Checksum\n\n\t\tfor _, metric := range resp.Metrics {\n\n\t\t\tif metric.Metric == g.URL_CHECK_HEALTH {\n\t\t\t\tarr := strings.Split(metric.Tags, \",\")\n\t\t\t\tif len(arr) != 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\turl := strings.Split(arr[0], \"=\")\n\t\t\t\tif len(url) != 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tstime := strings.Split(arr[1], \"=\")\n\t\t\t\tif len(stime) != 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif _, err := strconv.ParseInt(stime[1], 10, 64); err == nil {\n\t\t\t\t\turls[url[1]] = stime[1]\n\t\t\t\t} else {\n\t\t\t\t\tlog.Println(\"metric ParseInt timeout failed:\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif metric.Metric == g.NET_PORT_LISTEN {\n\t\t\t\tarr := strings.Split(metric.Tags, \"=\")\n\t\t\t\tif len(arr) != 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif port, err := strconv.ParseInt(arr[1], 10, 64); err == nil {\n\t\t\t\t\tports = append(ports, port)\n\t\t\t\t} else {\n\t\t\t\t\tlog.Println(\"metrics ParseInt failed:\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif metric.Metric == g.DU_BS {\n\t\t\t\tarr := strings.Split(metric.Tags, \"=\")\n\t\t\t\tif len(arr) != 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tpaths = append(paths, strings.TrimSpace(arr[1]))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif metric.Metric == g.PROC_NUM {\n\t\t\t\tarr := strings.Split(metric.Tags, \",\")\n\n\t\t\t\ttmpMap := make(map[int]string)\n\n\t\t\t\tfor i := 0; i < len(arr); i++ {\n\t\t\t\t\tif strings.HasPrefix(arr[i], \"name=\") {\n\t\t\t\t\t\ttmpMap[1] = strings.TrimSpace(arr[i][5:])\n\t\t\t\t\t} else if strings.HasPrefix(arr[i], \"cmdline=\") {\n\t\t\t\t\t\ttmpMap[2] = strings.TrimSpace(arr[i][8:])\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tprocs[metric.Tags] = tmpMap\n\t\t\t}\n\t\t}\n\n\t\tg.SetReportUrls(urls)\n\t\tg.SetReportPorts(ports)\n\t\tg.SetReportProcs(procs)\n\t\tg.SetDuPaths(paths)\n\n\t}\n}\n"
  },
  {
    "path": "modules/agent/cron/collector.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/funcs\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n)\n\nfunc InitDataHistory() {\n\tfor {\n\t\tfuncs.UpdateCpuStat()\n\t\tfuncs.UpdateDiskStats()\n\t\ttime.Sleep(g.COLLECT_INTERVAL)\n\t}\n}\n\nfunc Collect() {\n\n\tif !g.Config().Transfer.Enabled {\n\t\treturn\n\t}\n\n\tif len(g.Config().Transfer.Addrs) == 0 {\n\t\treturn\n\t}\n\n\tfor _, v := range funcs.Mappers {\n\t\tgo collect(int64(v.Interval), v.Fs)\n\t}\n}\n\nfunc collect(sec int64, fns []func() []*model.MetricValue) {\n\tt := time.NewTicker(time.Second * time.Duration(sec))\n\tdefer t.Stop()\n\tfor {\n\t\t<-t.C\n\n\t\thostname, err := g.Hostname()\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tmvs := []*model.MetricValue{}\n\t\tignoreMetrics := g.Config().IgnoreMetrics\n\n\t\tfor _, fn := range fns {\n\t\t\titems := fn()\n\t\t\tif items == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif len(items) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfor _, mv := range items {\n\t\t\t\tif b, ok := ignoreMetrics[mv.Metric]; ok && b {\n\t\t\t\t\tcontinue\n\t\t\t\t} else {\n\t\t\t\t\tmvs = append(mvs, mv)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tnow := time.Now().Unix()\n\t\tfor j := 0; j < len(mvs); j++ {\n\t\t\tmvs[j].Step = sec\n\t\t\tmvs[j].Endpoint = hostname\n\t\t\tmvs[j].Timestamp = now\n\t\t}\n\n\t\tg.SendToTransfer(mvs)\n\n\t}\n}\n"
  },
  {
    "path": "modules/agent/cron/ips.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"log\"\n\t\"time\"\n)\n\nfunc SyncTrustableIps() {\n\tif g.Config().Heartbeat.Enabled && g.Config().Heartbeat.Addr != \"\" {\n\t\tgo syncTrustableIps()\n\t}\n}\n\nfunc syncTrustableIps() {\n\n\tduration := time.Duration(g.Config().Heartbeat.Interval) * time.Second\n\n\tfor {\n\t\ttime.Sleep(duration)\n\n\t\tvar ips string\n\t\terr := g.HbsClient.Call(\"Agent.TrustableIps\", model.NullRpcRequest{}, &ips)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR: call Agent.TrustableIps fail\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tg.SetTrustableIps(ips)\n\t}\n}\n"
  },
  {
    "path": "modules/agent/cron/plugin.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/plugins\"\n\t\"github.com/toolkits/file\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc SyncMinePlugins() {\n\tif !g.Config().Plugin.Enabled {\n\t\treturn\n\t}\n\n\tif !g.Config().Heartbeat.Enabled {\n\t\treturn\n\t}\n\n\tif g.Config().Heartbeat.Addr == \"\" {\n\t\treturn\n\t}\n\n\tgo syncMinePlugins()\n}\n\nfunc syncMinePlugins() {\n\n\tvar (\n\t\ttimestamp  int64 = -1\n\t\tpluginDirs []string\n\t)\n\n\tduration := time.Duration(g.Config().Heartbeat.Interval) * time.Second\n\n\tfor {\n\t\ttime.Sleep(duration)\n\n\t\thostname, err := g.Hostname()\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\treq := model.AgentHeartbeatRequest{\n\t\t\tHostname: hostname,\n\t\t}\n\n\t\tvar resp model.AgentPluginsResponse\n\t\terr = g.HbsClient.Call(\"Agent.MinePlugins\", req, &resp)\n\t\tif err != nil {\n\t\t\tlog.Println(\"call Agent.MinePlugin fail:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif resp.Timestamp <= timestamp {\n\t\t\tcontinue\n\t\t}\n\n\t\tpluginDirs = resp.Plugins\n\t\ttimestamp = resp.Timestamp\n\n\t\tif g.Config().Debug {\n\t\t\tlog.Printf(\"call Agent.MinePlugin:%v\\n\", resp)\n\t\t}\n\n\t\tif len(pluginDirs) == 0 {\n\t\t\tplugins.ClearAllPlugins()\n\t\t\tcontinue\n\t\t}\n\n\t\tdesiredAll := make(map[string]*plugins.Plugin)\n\t\tfilefmt_scripts := [][]string{}\n\t\tdirfmt_scripts := []string{}\n\n\t\tfor _, script_path := range pluginDirs {\n\t\t\t//script_path could be a DIR or a SCRIPT_FILE_WITH_OR_WITHOUT_ARGS\n\t\t\t//比如： sys/ntp/60_ntp.py(arg1,arg2) 或者 sys/ntp/60_ntp.py 或者 sys/ntp\n\t\t\t//1. 参数只对单个脚本文件生效，目录不支持参数\n\t\t\t//2. 如果某个目录下的某个脚本被单独绑定到某个机器，那么再次绑定该目录时，该文件会不会再次执行\n\t\t\tvar args string = \"\"\n\n\t\t\tre := regexp.MustCompile(`(.*)\\((.*)\\)`)\n\t\t\tpath_args := re.FindAllStringSubmatch(script_path, -1)\n\t\t\tif path_args != nil {\n\t\t\t\tscript_path = path_args[0][1]\n\t\t\t\targs = path_args[0][2]\n\t\t\t}\n\n\t\t\tabs_path := filepath.Join(g.Config().Plugin.Dir, script_path)\n\t\t\tif !file.IsExist(abs_path) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif file.IsFile(abs_path) {\n\t\t\t\tfilefmt_scripts = append(filefmt_scripts, []string{script_path, args})\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdirfmt_scripts = append(dirfmt_scripts, script_path)\n\t\t}\n\n\t\ttaken := make(map[string]struct{})\n\t\tfor _, script_file := range filefmt_scripts {\n\t\t\tabs_path := filepath.Join(g.Config().Plugin.Dir, script_file[0])\n\t\t\t_, file_name := filepath.Split(abs_path)\n\t\t\tarr := strings.Split(file_name, \"_\")\n\t\t\tvar cycle int\n\t\t\tvar err error\n\t\t\tcycle, err = strconv.Atoi(arr[0])\n\t\t\tif err == nil {\n\t\t\t\tfi, _ := os.Stat(abs_path)\n\t\t\t\tplugin := &plugins.Plugin{FilePath: script_file[0], MTime: fi.ModTime().Unix(), Cycle: cycle, Args: script_file[1]}\n\t\t\t\tdesiredAll[script_file[0]+\"(\"+script_file[1]+\")\"] = plugin\n\t\t\t}\n\t\t\t//针对某个 hostgroup 绑定了单个脚本后，再绑定该脚本的目录时，会忽略目录中的该文件\n\t\t\ttaken[script_file[0]] = struct{}{}\n\t\t}\n\n\t\tfor _, script_path := range dirfmt_scripts {\n\t\t\tps := plugins.ListPlugins(strings.Trim(script_path, \"/\"))\n\t\t\tfor k, p := range ps {\n\t\t\t\tif _, ok := taken[k]; ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tdesiredAll[k] = p\n\t\t\t}\n\t\t}\n\n\t\tplugins.DelNoUsePlugins(desiredAll)\n\t\tplugins.AddNewPlugins(desiredAll)\n\n\t\tif g.Config().Debug {\n\t\t\tlog.Printf(\"current plugins:%v\\n\", plugins.Plugins)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/agent/cron/reporter.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"log\"\n\t\"time\"\n)\n\nfunc ReportAgentStatus() {\n\tif g.Config().Heartbeat.Enabled && g.Config().Heartbeat.Addr != \"\" {\n\t\tgo reportAgentStatus(time.Duration(g.Config().Heartbeat.Interval) * time.Second)\n\t}\n}\n\nfunc reportAgentStatus(interval time.Duration) {\n\tfor {\n\t\thostname, err := g.Hostname()\n\t\tif err != nil {\n\t\t\thostname = fmt.Sprintf(\"error:%s\", err.Error())\n\t\t}\n\n\t\treq := model.AgentReportRequest{\n\t\t\tHostname:      hostname,\n\t\t\tIP:            g.IP(),\n\t\t\tAgentVersion:  g.VersionMsg(),\n\t\t\tPluginVersion: g.GetCurrPluginVersion(),\n\t\t}\n\n\t\tvar resp model.SimpleRpcResponse\n\t\terr = g.HbsClient.Call(\"Agent.ReportStatus\", req, &resp)\n\t\tif err != nil || resp.Code != 0 {\n\t\t\tlog.Println(\"call Agent.ReportStatus fail:\", err, \"Request:\", req, \"Response:\", resp)\n\t\t}\n\n\t\ttime.Sleep(interval)\n\t}\n}\n"
  },
  {
    "path": "modules/agent/funcs/agent.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n)\n\nfunc AgentMetrics() []*model.MetricValue {\n\treturn []*model.MetricValue{GaugeValue(\"agent.alive\", 1)}\n}\n"
  },
  {
    "path": "modules/agent/funcs/checker.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"fmt\"\n\t\"github.com/toolkits/nux\"\n\t\"github.com/toolkits/sys\"\n)\n\nfunc CheckCollector() {\n\n\toutput := make(map[string]bool)\n\n\t_, procStatErr := nux.CurrentProcStat()\n\t_, listDiskErr := nux.ListDiskStats()\n\tports, listeningPortsErr := nux.ListeningPorts()\n\tprocs, psErr := nux.AllProcs()\n\n\t_, duErr := sys.CmdOut(\"du\", \"--help\")\n\n\toutput[\"kernel  \"] = len(KernelMetrics()) > 0\n\toutput[\"df.bytes\"] = DeviceMetricsCheck()\n\toutput[\"net.if  \"] = len(CoreNetMetrics([]string{})) > 0\n\toutput[\"loadavg \"] = len(LoadAvgMetrics()) > 0\n\toutput[\"cpustat \"] = procStatErr == nil\n\toutput[\"disk.io \"] = listDiskErr == nil\n\toutput[\"memory  \"] = len(MemMetrics()) > 0\n\toutput[\"netstat \"] = len(NetstatMetrics()) > 0\n\toutput[\"ss -s   \"] = len(SocketStatSummaryMetrics()) > 0\n\toutput[\"ss -tln \"] = listeningPortsErr == nil && len(ports) > 0\n\toutput[\"ps aux  \"] = psErr == nil && len(procs) > 0\n\toutput[\"du -bs  \"] = duErr == nil\n\n\tfor k, v := range output {\n\t\tstatus := \"fail\"\n\t\tif v {\n\t\t\tstatus = \"ok\"\n\t\t}\n\t\tfmt.Println(k, \"...\", status)\n\t}\n}\n"
  },
  {
    "path": "modules/agent/funcs/common.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"strings\"\n)\n\nfunc NewMetricValue(metric string, val interface{}, dataType string, tags ...string) *model.MetricValue {\n\tmv := model.MetricValue{\n\t\tMetric: metric,\n\t\tValue:  val,\n\t\tType:   dataType,\n\t}\n\n\tsize := len(tags)\n\n\tif size > 0 {\n\t\tmv.Tags = strings.Join(tags, \",\")\n\t}\n\n\treturn &mv\n}\n\nfunc GaugeValue(metric string, val interface{}, tags ...string) *model.MetricValue {\n\treturn NewMetricValue(metric, val, \"GAUGE\", tags...)\n}\n\nfunc CounterValue(metric string, val interface{}, tags ...string) *model.MetricValue {\n\treturn NewMetricValue(metric, val, \"COUNTER\", tags...)\n}\n"
  },
  {
    "path": "modules/agent/funcs/cpustat.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/nux\"\n\t\"sync\"\n)\n\nconst (\n\thistoryCount int = 2\n)\n\nvar (\n\tprocStatHistory [historyCount]*nux.ProcStat\n\tpsLock          = new(sync.RWMutex)\n)\n\nfunc UpdateCpuStat() error {\n\tps, err := nux.CurrentProcStat()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpsLock.Lock()\n\tdefer psLock.Unlock()\n\tfor i := historyCount - 1; i > 0; i-- {\n\t\tprocStatHistory[i] = procStatHistory[i-1]\n\t}\n\n\tprocStatHistory[0] = ps\n\treturn nil\n}\n\nfunc deltaTotal() uint64 {\n\tif procStatHistory[1] == nil {\n\t\treturn 0\n\t}\n\treturn procStatHistory[0].Cpu.Total - procStatHistory[1].Cpu.Total\n}\n\nfunc CpuIdle() float64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\tdt := deltaTotal()\n\tif dt == 0 {\n\t\treturn 0.0\n\t}\n\tinvQuotient := 100.00 / float64(dt)\n\treturn float64(procStatHistory[0].Cpu.Idle-procStatHistory[1].Cpu.Idle) * invQuotient\n}\n\nfunc CpuUser() float64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\tdt := deltaTotal()\n\tif dt == 0 {\n\t\treturn 0.0\n\t}\n\tinvQuotient := 100.00 / float64(dt)\n\treturn float64(procStatHistory[0].Cpu.User-procStatHistory[1].Cpu.User) * invQuotient\n}\n\nfunc CpuNice() float64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\tdt := deltaTotal()\n\tif dt == 0 {\n\t\treturn 0.0\n\t}\n\tinvQuotient := 100.00 / float64(dt)\n\treturn float64(procStatHistory[0].Cpu.Nice-procStatHistory[1].Cpu.Nice) * invQuotient\n}\n\nfunc CpuSystem() float64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\tdt := deltaTotal()\n\tif dt == 0 {\n\t\treturn 0.0\n\t}\n\tinvQuotient := 100.00 / float64(dt)\n\treturn float64(procStatHistory[0].Cpu.System-procStatHistory[1].Cpu.System) * invQuotient\n}\n\nfunc CpuIowait() float64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\tdt := deltaTotal()\n\tif dt == 0 {\n\t\treturn 0.0\n\t}\n\tinvQuotient := 100.00 / float64(dt)\n\treturn float64(procStatHistory[0].Cpu.Iowait-procStatHistory[1].Cpu.Iowait) * invQuotient\n}\n\nfunc CpuIrq() float64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\tdt := deltaTotal()\n\tif dt == 0 {\n\t\treturn 0.0\n\t}\n\tinvQuotient := 100.00 / float64(dt)\n\treturn float64(procStatHistory[0].Cpu.Irq-procStatHistory[1].Cpu.Irq) * invQuotient\n}\n\nfunc CpuSoftIrq() float64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\tdt := deltaTotal()\n\tif dt == 0 {\n\t\treturn 0.0\n\t}\n\tinvQuotient := 100.00 / float64(dt)\n\treturn float64(procStatHistory[0].Cpu.SoftIrq-procStatHistory[1].Cpu.SoftIrq) * invQuotient\n}\n\nfunc CpuSteal() float64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\tdt := deltaTotal()\n\tif dt == 0 {\n\t\treturn 0.0\n\t}\n\tinvQuotient := 100.00 / float64(dt)\n\treturn float64(procStatHistory[0].Cpu.Steal-procStatHistory[1].Cpu.Steal) * invQuotient\n}\n\nfunc CpuGuest() float64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\tdt := deltaTotal()\n\tif dt == 0 {\n\t\treturn 0.0\n\t}\n\tinvQuotient := 100.00 / float64(dt)\n\treturn float64(procStatHistory[0].Cpu.Guest-procStatHistory[1].Cpu.Guest) * invQuotient\n}\n\nfunc CurrentCpuSwitches() uint64 {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\treturn procStatHistory[0].Ctxt\n}\n\nfunc CpuPrepared() bool {\n\tpsLock.RLock()\n\tdefer psLock.RUnlock()\n\treturn procStatHistory[1] != nil\n}\n\nfunc CpuMetrics() []*model.MetricValue {\n\tif !CpuPrepared() {\n\t\treturn []*model.MetricValue{}\n\t}\n\n\tcpuIdleVal := CpuIdle()\n\tidle := GaugeValue(\"cpu.idle\", cpuIdleVal)\n\tbusy := GaugeValue(\"cpu.busy\", 100.0-cpuIdleVal)\n\tuser := GaugeValue(\"cpu.user\", CpuUser())\n\tnice := GaugeValue(\"cpu.nice\", CpuNice())\n\tsystem := GaugeValue(\"cpu.system\", CpuSystem())\n\tiowait := GaugeValue(\"cpu.iowait\", CpuIowait())\n\tirq := GaugeValue(\"cpu.irq\", CpuIrq())\n\tsoftirq := GaugeValue(\"cpu.softirq\", CpuSoftIrq())\n\tsteal := GaugeValue(\"cpu.steal\", CpuSteal())\n\tguest := GaugeValue(\"cpu.guest\", CpuGuest())\n\tswitches := CounterValue(\"cpu.switches\", CurrentCpuSwitches())\n\treturn []*model.MetricValue{idle, busy, user, nice, system, iowait, irq, softirq, steal, guest, switches}\n}\n"
  },
  {
    "path": "modules/agent/funcs/dfstat.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/toolkits/nux\"\n)\n\nfunc DeviceMetrics() (L []*model.MetricValue) {\n\tmountPoints, err := nux.ListMountPoint()\n\n\tif err != nil {\n\t\tlog.Error(\"collect device metrics fail:\", err)\n\t\treturn\n\t}\n\n\tvar myMountPoints map[string]bool = make(map[string]bool)\n\n\tif len(g.Config().Collector.MountPoint) > 0 {\n\t\tfor _, mp := range g.Config().Collector.MountPoint {\n\t\t\tmyMountPoints[mp] = true\n\t\t}\n\t}\n\n\tvar diskTotal uint64 = 0\n\tvar diskUsed uint64 = 0\n\n\tfor idx := range mountPoints {\n\t\tfsSpec, fsFile, fsVfstype := mountPoints[idx][0], mountPoints[idx][1], mountPoints[idx][2]\n\t\tif len(myMountPoints) > 0 {\n\t\t\tif _, ok := myMountPoints[fsFile]; !ok {\n\t\t\t\tlog.Debug(\"mount point not matched with config\", fsFile, \"ignored.\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tvar du *nux.DeviceUsage\n\t\tdu, err = nux.BuildDeviceUsage(fsSpec, fsFile, fsVfstype)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif du.BlocksAll == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tdiskTotal += du.BlocksAll\n\t\tdiskUsed += du.BlocksUsed\n\n\t\ttags := fmt.Sprintf(\"mount=%s,fstype=%s\", du.FsFile, du.FsVfstype)\n\t\tL = append(L, GaugeValue(\"df.bytes.total\", du.BlocksAll, tags))\n\t\tL = append(L, GaugeValue(\"df.bytes.used\", du.BlocksUsed, tags))\n\t\tL = append(L, GaugeValue(\"df.bytes.free\", du.BlocksFree, tags))\n\t\tL = append(L, GaugeValue(\"df.bytes.used.percent\", du.BlocksUsedPercent, tags))\n\t\tL = append(L, GaugeValue(\"df.bytes.free.percent\", du.BlocksFreePercent, tags))\n\n\t\tif du.InodesAll == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tL = append(L, GaugeValue(\"df.inodes.total\", du.InodesAll, tags))\n\t\tL = append(L, GaugeValue(\"df.inodes.used\", du.InodesUsed, tags))\n\t\tL = append(L, GaugeValue(\"df.inodes.free\", du.InodesFree, tags))\n\t\tL = append(L, GaugeValue(\"df.inodes.used.percent\", du.InodesUsedPercent, tags))\n\t\tL = append(L, GaugeValue(\"df.inodes.free.percent\", du.InodesFreePercent, tags))\n\n\t}\n\n\tif len(L) > 0 && diskTotal > 0 {\n\t\tL = append(L, GaugeValue(\"df.statistics.total\", float64(diskTotal)))\n\t\tL = append(L, GaugeValue(\"df.statistics.used\", float64(diskUsed)))\n\t\tL = append(L, GaugeValue(\"df.statistics.used.percent\", float64(diskUsed)*100.0/float64(diskTotal)))\n\t}\n\n\treturn\n}\n\nfunc DeviceMetricsCheck() bool {\n\tmountPoints, err := nux.ListMountPoint()\n\n\tif err != nil {\n\t\tlog.Error(\"collect device metrics fail:\", err)\n\t\treturn false\n\t}\n\n\tif len(mountPoints) <= 0 {\n\t\treturn false\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "modules/agent/funcs/diskstats.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/nux\"\n)\n\nvar (\n\tdiskStatsMap = make(map[string][2]*nux.DiskStats)\n\tdsLock       = new(sync.RWMutex)\n)\n\nfunc UpdateDiskStats() error {\n\tdsList, err := nux.ListDiskStats()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdsLock.Lock()\n\tdefer dsLock.Unlock()\n\tfor i := 0; i < len(dsList); i++ {\n\t\tdevice := dsList[i].Device\n\t\tdiskStatsMap[device] = [2]*nux.DiskStats{dsList[i], diskStatsMap[device][0]}\n\t}\n\treturn nil\n}\n\nfunc IOReadRequests(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].ReadRequests - arr[1].ReadRequests\n}\n\nfunc IOReadMerged(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].ReadMerged - arr[1].ReadMerged\n}\n\nfunc IOReadSectors(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].ReadSectors - arr[1].ReadSectors\n}\n\nfunc IOMsecRead(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].MsecRead - arr[1].MsecRead\n}\n\nfunc IOWriteRequests(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].WriteRequests - arr[1].WriteRequests\n}\n\nfunc IOWriteMerged(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].WriteMerged - arr[1].WriteMerged\n}\n\nfunc IOWriteSectors(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].WriteSectors - arr[1].WriteSectors\n}\n\nfunc IOMsecWrite(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].MsecWrite - arr[1].MsecWrite\n}\n\nfunc IOMsecTotal(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].MsecTotal - arr[1].MsecTotal\n}\n\nfunc IOMsecWeightedTotal(arr [2]*nux.DiskStats) uint64 {\n\treturn arr[0].MsecWeightedTotal - arr[1].MsecWeightedTotal\n}\n\nfunc TS(arr [2]*nux.DiskStats) uint64 {\n\treturn uint64(arr[0].TS.Sub(arr[1].TS).Nanoseconds() / 1000000)\n}\n\nfunc IODelta(device string, f func([2]*nux.DiskStats) uint64) uint64 {\n\tval, ok := diskStatsMap[device]\n\tif !ok {\n\t\treturn 0\n\t}\n\n\tif val[1] == nil {\n\t\treturn 0\n\t}\n\treturn f(val)\n}\n\nfunc DiskIOMetrics() (L []*model.MetricValue) {\n\n\tdsList, err := nux.ListDiskStats()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn\n\t}\n\n\tfor _, ds := range dsList {\n\t\tif !ShouldHandleDevice(ds.Device) {\n\t\t\tcontinue\n\t\t}\n\n\t\tdevice := \"device=\" + ds.Device\n\n\t\tL = append(L, CounterValue(\"disk.io.read_requests\", ds.ReadRequests, device))\n\t\tL = append(L, CounterValue(\"disk.io.read_merged\", ds.ReadMerged, device))\n\t\tL = append(L, CounterValue(\"disk.io.read_sectors\", ds.ReadSectors, device))\n\t\tL = append(L, CounterValue(\"disk.io.msec_read\", ds.MsecRead, device))\n\t\tL = append(L, CounterValue(\"disk.io.write_requests\", ds.WriteRequests, device))\n\t\tL = append(L, CounterValue(\"disk.io.write_merged\", ds.WriteMerged, device))\n\t\tL = append(L, CounterValue(\"disk.io.write_sectors\", ds.WriteSectors, device))\n\t\tL = append(L, CounterValue(\"disk.io.msec_write\", ds.MsecWrite, device))\n\t\tL = append(L, CounterValue(\"disk.io.ios_in_progress\", ds.IosInProgress, device))\n\t\tL = append(L, CounterValue(\"disk.io.msec_total\", ds.MsecTotal, device))\n\t\tL = append(L, CounterValue(\"disk.io.msec_weighted_total\", ds.MsecWeightedTotal, device))\n\t}\n\treturn\n}\n\nfunc IOStatsMetrics() (L []*model.MetricValue) {\n\tdsLock.RLock()\n\tdefer dsLock.RUnlock()\n\n\tfor device := range diskStatsMap {\n\t\tif !ShouldHandleDevice(device) {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := \"device=\" + device\n\t\trio := IODelta(device, IOReadRequests)\n\t\twio := IODelta(device, IOWriteRequests)\n\t\tdelta_rsec := IODelta(device, IOReadSectors)\n\t\tdelta_wsec := IODelta(device, IOWriteSectors)\n\t\truse := IODelta(device, IOMsecRead)\n\t\twuse := IODelta(device, IOMsecWrite)\n\t\tuse := IODelta(device, IOMsecTotal)\n\t\tn_io := rio + wio\n\t\tavgrq_sz := 0.0\n\t\tawait := 0.0\n\t\tsvctm := 0.0\n\t\tif n_io != 0 {\n\t\t\tavgrq_sz = float64(delta_rsec+delta_wsec) / float64(n_io)\n\t\t\tawait = float64(ruse+wuse) / float64(n_io)\n\t\t\tsvctm = float64(use) / float64(n_io)\n\t\t}\n\n\t\tduration := IODelta(device, TS)\n\n\t\tL = append(L, GaugeValue(\"disk.io.read_bytes\", float64(delta_rsec)*512.0, tags))\n\t\tL = append(L, GaugeValue(\"disk.io.write_bytes\", float64(delta_wsec)*512.0, tags))\n\t\tL = append(L, GaugeValue(\"disk.io.avgrq_sz\", avgrq_sz, tags))\n\t\tL = append(L, GaugeValue(\"disk.io.avgqu-sz\", float64(IODelta(device, IOMsecWeightedTotal))/1000.0, tags))\n\t\tL = append(L, GaugeValue(\"disk.io.await\", await, tags))\n\t\tL = append(L, GaugeValue(\"disk.io.svctm\", svctm, tags))\n\t\ttmp := float64(use) * 100.0 / float64(duration)\n\t\tif tmp > 100.0 {\n\t\t\ttmp = 100.0\n\t\t}\n\t\tL = append(L, GaugeValue(\"disk.io.util\", tmp, tags))\n\t}\n\n\treturn\n}\n\nfunc IOStatsForPage() (L [][]string) {\n\tdsLock.RLock()\n\tdefer dsLock.RUnlock()\n\n\tfor device := range diskStatsMap {\n\t\tif !ShouldHandleDevice(device) {\n\t\t\tcontinue\n\t\t}\n\n\t\trio := IODelta(device, IOReadRequests)\n\t\twio := IODelta(device, IOWriteRequests)\n\n\t\tdelta_rsec := IODelta(device, IOReadSectors)\n\t\tdelta_wsec := IODelta(device, IOWriteSectors)\n\n\t\truse := IODelta(device, IOMsecRead)\n\t\twuse := IODelta(device, IOMsecWrite)\n\t\tuse := IODelta(device, IOMsecTotal)\n\t\tn_io := rio + wio\n\t\tavgrq_sz := 0.0\n\t\tawait := 0.0\n\t\tsvctm := 0.0\n\t\tif n_io != 0 {\n\t\t\tavgrq_sz = float64(delta_rsec+delta_wsec) / float64(n_io)\n\t\t\tawait = float64(ruse+wuse) / float64(n_io)\n\t\t\tsvctm = float64(use) / float64(n_io)\n\t\t}\n\n\t\titem := []string{\n\t\t\tdevice,\n\t\t\tfmt.Sprintf(\"%d\", IODelta(device, IOReadMerged)),\n\t\t\tfmt.Sprintf(\"%d\", IODelta(device, IOWriteMerged)),\n\t\t\tfmt.Sprintf(\"%d\", rio),\n\t\t\tfmt.Sprintf(\"%d\", wio),\n\t\t\tfmt.Sprintf(\"%.2f\", float64(delta_rsec)/2.0),\n\t\t\tfmt.Sprintf(\"%.2f\", float64(delta_wsec)/2.0),\n\t\t\tfmt.Sprintf(\"%.2f\", avgrq_sz),                                             // avgrq-sz: delta(rsect+wsect)/delta(rio+wio)\n\t\t\tfmt.Sprintf(\"%.2f\", float64(IODelta(device, IOMsecWeightedTotal))/1000.0), // avgqu-sz: delta(aveq)/s/1000\n\t\t\tfmt.Sprintf(\"%.2f\", await),                                                // await: delta(ruse+wuse)/delta(rio+wio)\n\t\t\tfmt.Sprintf(\"%.2f\", svctm),                                                // svctm: delta(use)/delta(rio+wio)\n\t\t\tfmt.Sprintf(\"%.2f%%\", float64(use)/10.0),                                  // %util: delta(use)/s/1000 * 100%\n\t\t}\n\t\tL = append(L, item)\n\t}\n\n\treturn\n}\n\nfunc ShouldHandleDevice(device string) bool {\n\tnormal := len(device) <= 4 && (strings.HasPrefix(device, \"sd\") || strings.HasPrefix(device, \"vd\")) && !strings.ContainsAny(device, \"1234\")\n\taws := len(device) >= 4 && strings.HasPrefix(device, \"xvd\")\n\tflash := len(device) >= 4 && (strings.HasPrefix(device, \"fio\") || strings.HasPrefix(device, \"nvme\"))\n\tnbd := len(device) >= 4 && strings.HasPrefix(device, \"nbd\")\n\treturn normal || aws || flash || nbd\n}\n"
  },
  {
    "path": "modules/agent/funcs/du.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/sys\"\n)\n\nvar timeout = 30\n\nfunc DuMetrics() (L []*model.MetricValue) {\n\tpaths := g.DuPaths()\n\tresult := make(chan *model.MetricValue, len(paths))\n\tvar wg sync.WaitGroup\n\n\tfor _, path := range paths {\n\t\twg.Add(1)\n\t\tgo func(path string) {\n\t\t\tvar err error\n\t\t\tdefer func() {\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Println(err)\n\t\t\t\t\tresult <- GaugeValue(g.DU_BS, -1, \"path=\"+path)\n\t\t\t\t}\n\t\t\t\twg.Done()\n\t\t\t}()\n\t\t\t//tips:osx  does not support -b.\n\t\t\tcmd := exec.Command(\"du\", \"-bs\", path)\n\t\t\tvar stdout bytes.Buffer\n\t\t\tcmd.Stdout = &stdout\n\t\t\tvar stderr bytes.Buffer\n\t\t\tcmd.Stderr = &stderr\n\t\t\terr = cmd.Start()\n\t\t\tif err != nil {\n\t\t\t\treturn\n\n\t\t\t}\n\t\t\terr, isTimeout := sys.CmdRunWithTimeout(cmd, time.Duration(timeout)*time.Second)\n\t\t\tif isTimeout {\n\t\t\t\terr = errors.New(fmt.Sprintf(\"exec cmd : du -bs %s timeout\", path))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\terrStr := stderr.String()\n\t\t\tif errStr != \"\" {\n\t\t\t\terr = errors.New(errStr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\terr = errors.New(fmt.Sprintf(\"du -bs %s failed: %s\", path, err.Error()))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tarr := strings.Fields(stdout.String())\n\t\t\tif len(arr) < 2 {\n\t\t\t\terr = errors.New(fmt.Sprintf(\"du -bs %s failed: %s\", path, \"return fields < 2\"))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tsize, err := strconv.ParseUint(arr[0], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\terr = errors.New(fmt.Sprintf(\"cannot parse du -bs %s output\", path))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tresult <- GaugeValue(g.DU_BS, size, \"path=\"+path)\n\t\t}(path)\n\t}\n\twg.Wait()\n\n\tresultLen := len(result)\n\tfor i := 0; i < resultLen; i++ {\n\t\tL = append(L, <-result)\n\t}\n\treturn\n}\n"
  },
  {
    "path": "modules/agent/funcs/du_test.go",
    "content": "package funcs\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\nvar testPath = \"\"\n\nfunc init() {\n\tdir, err := filepath.Abs(filepath.Dir(os.Args[0]))\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n\ttestPath = dir\n\n}\n\nfunc TestDuMetrics(t *testing.T) {\n\tpaths := []string{testPath}\n\tg.SetDuPaths(paths)\n\tduMetrics := DuMetrics()\n\tif duMetrics[0].Value == -1 {\n\t\tt.Error(\"expect metric value > 0 ,but -1\")\n\t}\n}\n\nfunc TestDuMetricsPathNotExist(t *testing.T) {\n\tpaths := []string{\"'path does not exist'\"}\n\tg.SetDuPaths(paths)\n\tduMetrics := DuMetrics()\n\tif len(duMetrics) != 1 || duMetrics[0].Value != -1 {\n\t\tt.Errorf(\"metric value expect -1, but metric : %v\", duMetrics)\n\t}\n}\n\nfunc TestDuMetricsTimeout(t *testing.T) {\n\ttimeout = 0\n\tpaths := []string{testPath}\n\tg.SetDuPaths(paths)\n\tduMetrics := DuMetrics()\n\tif len(duMetrics) != 1 || duMetrics[0].Value != -1 {\n\t\tt.Errorf(\"metric value expect -1, but metric : %v\", duMetrics)\n\t}\n}\n"
  },
  {
    "path": "modules/agent/funcs/funcs.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n)\n\ntype FuncsAndInterval struct {\n\tFs       []func() []*model.MetricValue\n\tInterval int\n}\n\nvar Mappers []FuncsAndInterval\n\nfunc BuildMappers() {\n\tinterval := g.Config().Transfer.Interval\n\tMappers = []FuncsAndInterval{\n\t\t{\n\t\t\tFs: []func() []*model.MetricValue{\n\t\t\t\tAgentMetrics,\n\t\t\t\tCpuMetrics,\n\t\t\t\tNetMetrics,\n\t\t\t\tKernelMetrics,\n\t\t\t\tLoadAvgMetrics,\n\t\t\t\tMemMetrics,\n\t\t\t\tDiskIOMetrics,\n\t\t\t\tIOStatsMetrics,\n\t\t\t\tNetstatMetrics,\n\t\t\t\tProcMetrics,\n\t\t\t\tUdpMetrics,\n\t\t\t},\n\t\t\tInterval: interval,\n\t\t},\n\t\t{\n\t\t\tFs: []func() []*model.MetricValue{\n\t\t\t\tDeviceMetrics,\n\t\t\t},\n\t\t\tInterval: interval,\n\t\t},\n\t\t{\n\t\t\tFs: []func() []*model.MetricValue{\n\t\t\t\tPortMetrics,\n\t\t\t\tSocketStatSummaryMetrics,\n\t\t\t},\n\t\t\tInterval: interval,\n\t\t},\n\t\t{\n\t\t\tFs: []func() []*model.MetricValue{\n\t\t\t\tDuMetrics,\n\t\t\t},\n\t\t\tInterval: interval,\n\t\t},\n\t\t{\n\t\t\tFs: []func() []*model.MetricValue{\n\t\t\t\tUrlMetrics,\n\t\t\t},\n\t\t\tInterval: interval,\n\t\t},\n\t\t{\n\t\t\tFs: []func() []*model.MetricValue{\n\t\t\t\tGpuMetrics,\n\t\t\t},\n\t\t\tInterval: interval,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "modules/agent/funcs/gpu.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"log\"\n\n\t\"github.com/mindprince/gonvml\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n)\n\n// 需要load libnvidia-ml.so.1库\nfunc GpuMetrics() (L []*model.MetricValue) {\n\n\tif err := gonvml.Initialize(); err != nil {\n\t\tdebug := g.Config().Debug\n\t\tif debug {\n\t\t\tlog.Println(\"Initialize error: \", err)\n\t\t}\n\t\treturn\n\t}\n\n\tdefer gonvml.Shutdown()\n\n\tcount, err := gonvml.DeviceCount()\n\tif err != nil {\n\t\tlog.Println(\"DeviceCount error: \", err)\n\t\treturn\n\t}\n\n\tif count == 0 {\n\t\treturn\n\t}\n\n\ttemperature := uint(0)\n\ttotalMemory := uint64(0)\n\tusedMemory := uint64(0)\n\tgpuUtilization := uint(0)\n\tmemoryUtilization := uint(0)\n\tpowerUsage := uint(0)\n\tallUtilization := uint(0)\n\tallMemoryUtilization := uint(0)\n\n\tfor i := 0; i < int(count); i++ {\n\t\tdev, err := gonvml.DeviceHandleByIndex(uint(i))\n\t\tif err != nil {\n\t\t\tlog.Println(\"DeviceHandleByIndex error:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tuuid, err := dev.UUID()\n\t\tif err != nil {\n\t\t\tlog.Println(\"dev.UUID error\", err)\n\t\t}\n\n\t\ttag := \"uuid=\" + uuid\n\n\t\t// 不是所有gpu都有风扇\n\t\tfanSpeed, err := dev.FanSpeed()\n\t\tif err != nil {\n\t\t\tlog.Println(\"dev.FanSpeed error: \", err)\n\t\t} else {\n\t\t\tL = append(L, GaugeValue(\"gpu.fan.speed\", fanSpeed, tag))\n\t\t}\n\n\t\ttemperature, err = dev.Temperature()\n\t\tif err != nil {\n\t\t\tlog.Println(\"dev.Temperature error: \", err)\n\t\t\tcontinue\n\t\t}\n\n\t\ttotalMemory, usedMemory, err = dev.MemoryInfo()\n\t\tif err != nil {\n\t\t\tlog.Println(\"dev.MemoryInfo error: \", err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// 单位换算为兆\n\t\ttotalBillion := float64(totalMemory / 1024 / 1024)\n\t\tusedBillion := float64(usedMemory / 1024 / 1024)\n\n\t\tgpuUtilization, memoryUtilization, err = dev.UtilizationRates()\n\t\tif err != nil {\n\t\t\tlog.Println(\"dev.UtilizationRates error: \", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tallUtilization += gpuUtilization\n\t\tallMemoryUtilization += memoryUtilization\n\n\t\tpowerUsage, err = dev.PowerUsage()\n\t\tif err != nil {\n\t\t\tlog.Println(\"dev.PowerUsage error: \", err)\n\t\t}\n\n\t\t// 单位换算为瓦特\n\t\tpowerWatt := float64(powerUsage / 1000)\n\n\t\tL = append(L, GaugeValue(\"gpu.temperature\", temperature, tag))\n\t\tL = append(L, GaugeValue(\"gpu.memory.total\", totalBillion, tag))\n\t\tL = append(L, GaugeValue(\"gpu.memory.used\", usedBillion, tag))\n\t\tL = append(L, GaugeValue(\"gpu.memory.util\", memoryUtilization, tag))\n\t\tL = append(L, GaugeValue(\"gpu.util\", gpuUtilization, tag))\n\t\tL = append(L, GaugeValue(\"gpu.power.usage\", powerWatt, tag))\n\t}\n\n\tL = append(L, GaugeValue(\"gpu.count\", count))\n\tL = append(L, GaugeValue(\"gpu.util.avg\", allUtilization/count))\n\tL = append(L, GaugeValue(\"gpu.memory.util.avg\", allMemoryUtilization/count))\n\treturn L\n}\n"
  },
  {
    "path": "modules/agent/funcs/ifstat.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/nux\"\n\t\"log\"\n)\n\nfunc NetMetrics() []*model.MetricValue {\n\treturn CoreNetMetrics(g.Config().Collector.IfacePrefix)\n}\n\nfunc CoreNetMetrics(ifacePrefix []string) []*model.MetricValue {\n\n\tnetIfs, err := nux.NetIfs(ifacePrefix)\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn []*model.MetricValue{}\n\t}\n\n\tcnt := len(netIfs)\n\tret := make([]*model.MetricValue, cnt*26)\n\n\tfor idx, netIf := range netIfs {\n\t\tiface := \"iface=\" + netIf.Iface\n\t\tret[idx*26+0] = CounterValue(\"net.if.in.bytes\", netIf.InBytes, iface)\n\t\tret[idx*26+1] = CounterValue(\"net.if.in.packets\", netIf.InPackages, iface)\n\t\tret[idx*26+2] = CounterValue(\"net.if.in.errors\", netIf.InErrors, iface)\n\t\tret[idx*26+3] = CounterValue(\"net.if.in.dropped\", netIf.InDropped, iface)\n\t\tret[idx*26+4] = CounterValue(\"net.if.in.fifo.errs\", netIf.InFifoErrs, iface)\n\t\tret[idx*26+5] = CounterValue(\"net.if.in.frame.errs\", netIf.InFrameErrs, iface)\n\t\tret[idx*26+6] = CounterValue(\"net.if.in.compressed\", netIf.InCompressed, iface)\n\t\tret[idx*26+7] = CounterValue(\"net.if.in.multicast\", netIf.InMulticast, iface)\n\t\tret[idx*26+8] = CounterValue(\"net.if.out.bytes\", netIf.OutBytes, iface)\n\t\tret[idx*26+9] = CounterValue(\"net.if.out.packets\", netIf.OutPackages, iface)\n\t\tret[idx*26+10] = CounterValue(\"net.if.out.errors\", netIf.OutErrors, iface)\n\t\tret[idx*26+11] = CounterValue(\"net.if.out.dropped\", netIf.OutDropped, iface)\n\t\tret[idx*26+12] = CounterValue(\"net.if.out.fifo.errs\", netIf.OutFifoErrs, iface)\n\t\tret[idx*26+13] = CounterValue(\"net.if.out.collisions\", netIf.OutCollisions, iface)\n\t\tret[idx*26+14] = CounterValue(\"net.if.out.carrier.errs\", netIf.OutCarrierErrs, iface)\n\t\tret[idx*26+15] = CounterValue(\"net.if.out.compressed\", netIf.OutCompressed, iface)\n\t\tret[idx*26+16] = CounterValue(\"net.if.total.bytes\", netIf.TotalBytes, iface)\n\t\tret[idx*26+17] = CounterValue(\"net.if.total.packets\", netIf.TotalPackages, iface)\n\t\tret[idx*26+18] = CounterValue(\"net.if.total.errors\", netIf.TotalErrors, iface)\n\t\tret[idx*26+19] = CounterValue(\"net.if.total.dropped\", netIf.TotalDropped, iface)\n\t\tret[idx*26+20] = GaugeValue(\"net.if.speed.bits\", netIf.SpeedBits, iface)\n\t\tret[idx*26+21] = CounterValue(\"net.if.in.percent\", netIf.InPercent, iface)\n\t\tret[idx*26+22] = CounterValue(\"net.if.out.percent\", netIf.OutPercent, iface)\n\t\tret[idx*26+23] = CounterValue(\"net.if.in.bits\", netIf.InBytes*8, iface)\n\t\tret[idx*26+24] = CounterValue(\"net.if.out.bits\", netIf.OutBytes*8, iface)\n\t\tret[idx*26+25] = CounterValue(\"net.if.total.bits\", netIf.TotalBytes*8, iface)\n\t}\n\treturn ret\n}\n"
  },
  {
    "path": "modules/agent/funcs/kernel.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/nux\"\n\t\"log\"\n)\n\nfunc KernelMetrics() (L []*model.MetricValue) {\n\n\tmaxFiles, err := nux.KernelMaxFiles()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn\n\t}\n\n\tL = append(L, GaugeValue(\"kernel.maxfiles\", maxFiles))\n\n\tmaxProc, err := nux.KernelMaxProc()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn\n\t}\n\n\tL = append(L, GaugeValue(\"kernel.maxproc\", maxProc))\n\n\tallocateFiles, err := nux.KernelAllocateFiles()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn\n\t}\n\n\tL = append(L, GaugeValue(\"kernel.files.allocated\", allocateFiles))\n\tL = append(L, GaugeValue(\"kernel.files.left\", maxFiles-allocateFiles))\n\treturn\n}\n"
  },
  {
    "path": "modules/agent/funcs/loadavg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/nux\"\n\t\"log\"\n)\n\nfunc LoadAvgMetrics() []*model.MetricValue {\n\tload, err := nux.LoadAvg()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn nil\n\t}\n\n\treturn []*model.MetricValue{\n\t\tGaugeValue(\"load.1min\", load.Avg1min),\n\t\tGaugeValue(\"load.5min\", load.Avg5min),\n\t\tGaugeValue(\"load.15min\", load.Avg15min),\n\t}\n\n}\n"
  },
  {
    "path": "modules/agent/funcs/meminfo.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/nux\"\n\t\"log\"\n)\n\nfunc MemMetrics() []*model.MetricValue {\n\tm, err := nux.MemInfo()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn nil\n\t}\n\n\tmemFree := m.MemFree + m.Buffers + m.Cached\n\tif m.MemAvailable > 0 {\n\t\tmemFree = m.MemAvailable\n\t}\n\tmemUsed := m.MemTotal - memFree\n\n\tpmemFree := 0.0\n\tpmemUsed := 0.0\n\tif m.MemTotal != 0 {\n\t\tpmemFree = float64(memFree) * 100.0 / float64(m.MemTotal)\n\t\tpmemUsed = float64(memUsed) * 100.0 / float64(m.MemTotal)\n\t}\n\n\tpswapFree := 0.0\n\tpswapUsed := 0.0\n\tif m.SwapTotal != 0 {\n\t\tpswapFree = float64(m.SwapFree) * 100.0 / float64(m.SwapTotal)\n\t\tpswapUsed = float64(m.SwapUsed) * 100.0 / float64(m.SwapTotal)\n\t}\n\n\treturn []*model.MetricValue{\n\t\tGaugeValue(\"mem.memtotal\", m.MemTotal),\n\t\tGaugeValue(\"mem.memused\", memUsed),\n\t\tGaugeValue(\"mem.memfree\", memFree),\n\t\tGaugeValue(\"mem.swaptotal\", m.SwapTotal),\n\t\tGaugeValue(\"mem.swapused\", m.SwapUsed),\n\t\tGaugeValue(\"mem.swapfree\", m.SwapFree),\n\t\tGaugeValue(\"mem.memfree.percent\", pmemFree),\n\t\tGaugeValue(\"mem.memused.percent\", pmemUsed),\n\t\tGaugeValue(\"mem.swapfree.percent\", pswapFree),\n\t\tGaugeValue(\"mem.swapused.percent\", pswapUsed),\n\t}\n\n}\n"
  },
  {
    "path": "modules/agent/funcs/netstat.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/nux\"\n\t\"log\"\n)\n\nvar USES = map[string]struct{}{\n\t\"PruneCalled\":        {},\n\t\"LockDroppedIcmps\":   {},\n\t\"ArpFilter\":          {},\n\t\"TW\":                 {},\n\t\"DelayedACKLocked\":   {},\n\t\"ListenOverflows\":    {},\n\t\"ListenDrops\":        {},\n\t\"TCPPrequeueDropped\": {},\n\t\"TCPTSReorder\":       {},\n\t\"TCPDSACKUndo\":       {},\n\t\"TCPLoss\":            {},\n\t\"TCPLostRetransmit\":  {},\n\t\"TCPLossFailures\":    {},\n\t\"TCPFastRetrans\":     {},\n\t\"TCPTimeouts\":        {},\n\t\"TCPSchedulerFailed\": {},\n\t\"TCPAbortOnMemory\":   {},\n\t\"TCPAbortOnTimeout\":  {},\n\t\"TCPAbortFailed\":     {},\n\t\"TCPMemoryPressures\": {},\n\t\"TCPSpuriousRTOs\":    {},\n\t\"TCPBacklogDrop\":     {},\n\t\"TCPMinTTLDrop\":      {},\n}\n\nfunc NetstatMetrics() (L []*model.MetricValue) {\n\ttcpExts, err := nux.Netstat(\"TcpExt\")\n\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn\n\t}\n\n\tcnt := len(tcpExts)\n\tif cnt == 0 {\n\t\treturn\n\t}\n\n\tfor key, val := range tcpExts {\n\t\tif _, ok := USES[key]; !ok {\n\t\t\tcontinue\n\t\t}\n\t\tL = append(L, CounterValue(\"TcpExt.\"+key, val))\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "modules/agent/funcs/portstat.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/nux\"\n\t\"github.com/toolkits/slice\"\n\t\"log\"\n)\n\nfunc PortMetrics() (L []*model.MetricValue) {\n\n\treportPorts := g.ReportPorts()\n\tsz := len(reportPorts)\n\tif sz == 0 {\n\t\treturn\n\t}\n\n\tallTcpPorts, err := nux.TcpPorts()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn\n\t}\n\n\tallUdpPorts, err := nux.UdpPorts()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn\n\t}\n\n\tfor i := 0; i < sz; i++ {\n\t\ttags := fmt.Sprintf(\"port=%d\", reportPorts[i])\n\t\tif slice.ContainsInt64(allTcpPorts, reportPorts[i]) || slice.ContainsInt64(allUdpPorts, reportPorts[i]) {\n\t\t\tL = append(L, GaugeValue(g.NET_PORT_LISTEN, 1, tags))\n\t\t} else {\n\t\t\tL = append(L, GaugeValue(g.NET_PORT_LISTEN, 0, tags))\n\t\t}\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "modules/agent/funcs/procs.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/nux\"\n\t\"log\"\n\t\"strings\"\n)\n\nfunc ProcMetrics() (L []*model.MetricValue) {\n\n\treportProcs := g.ReportProcs()\n\tsz := len(reportProcs)\n\tif sz == 0 {\n\t\treturn\n\t}\n\n\tps, err := nux.AllProcs()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn\n\t}\n\n\tpslen := len(ps)\n\n\tfor tags, m := range reportProcs {\n\t\tcnt := 0\n\t\tfor i := 0; i < pslen; i++ {\n\t\t\tif is_a(ps[i], m) {\n\t\t\t\tcnt++\n\t\t\t}\n\t\t}\n\n\t\tL = append(L, GaugeValue(g.PROC_NUM, cnt, tags))\n\t}\n\n\treturn\n}\n\nfunc is_a(p *nux.Proc, m map[int]string) bool {\n\t// only one kv pair\n\tfor key, val := range m {\n\t\tif key == 1 {\n\t\t\t// name\n\t\t\tif val != p.Name {\n\t\t\t\treturn false\n\t\t\t}\n\t\t} else if key == 2 {\n\t\t\t// cmdline\n\t\t\tif !strings.Contains(p.Cmdline, val) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "modules/agent/funcs/snmp.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/nux\"\n\t\"log\"\n)\n\nfunc UdpMetrics() []*model.MetricValue {\n\tudp, err := nux.Snmp(\"Udp\")\n\tif err != nil {\n\t\tlog.Println(\"read snmp fail\", err)\n\t\treturn []*model.MetricValue{}\n\t}\n\n\tcount := len(udp)\n\tret := make([]*model.MetricValue, count)\n\ti := 0\n\tfor key, val := range udp {\n\t\tret[i] = CounterValue(\"snmp.Udp.\"+key, val)\n\t\ti++\n\t}\n\n\treturn ret\n}\n"
  },
  {
    "path": "modules/agent/funcs/sockstat.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/nux\"\n\t\"log\"\n)\n\nfunc SocketStatSummaryMetrics() (L []*model.MetricValue) {\n\tssMap, err := nux.SocketStatSummary()\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn\n\t}\n\n\tfor k, v := range ssMap {\n\t\tL = append(L, GaugeValue(\"ss.\"+k, v))\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "modules/agent/funcs/urlstat.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage funcs\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/file\"\n\t\"github.com/toolkits/sys\"\n)\n\nfunc UrlMetrics() (L []*model.MetricValue) {\n\treportUrls := g.ReportUrls()\n\tsz := len(reportUrls)\n\tif sz == 0 {\n\t\treturn\n\t}\n\thostname, err := g.Hostname()\n\tif err != nil {\n\t\thostname = \"None\"\n\t}\n\tfor furl, timeout := range reportUrls {\n\t\ttags := fmt.Sprintf(\"url=%v,timeout=%v,src=%v\", furl, timeout, hostname)\n\t\tif ok, _ := probeUrl(furl, timeout); !ok {\n\t\t\tL = append(L, GaugeValue(g.URL_CHECK_HEALTH, 0, tags))\n\t\t\tcontinue\n\t\t}\n\t\tL = append(L, GaugeValue(g.URL_CHECK_HEALTH, 1, tags))\n\t}\n\treturn\n}\n\nfunc probeUrl(furl string, timeout string) (bool, error) {\n\tbs, err := sys.CmdOutBytes(\"curl\", \"--max-filesize\", \"102400\", \"-I\", \"-m\", timeout, \"-o\", \"/dev/null\", \"-s\", \"-w\", \"%{http_code}\", furl)\n\tif err != nil {\n\t\tlog.Printf(\"probe url [%v] failed.the err is: [%v]\\n\", furl, err)\n\t\treturn false, err\n\t}\n\treader := bufio.NewReader(bytes.NewBuffer(bs))\n\tretcode, err := file.ReadLine(reader)\n\tif err != nil {\n\t\tlog.Println(\"read retcode failed.err is:\", err)\n\t\treturn false, err\n\t}\n\tif strings.TrimSpace(string(retcode)) != \"200\" {\n\t\tlog.Printf(\"return code [%v] is not 200.query url is [%v]\", string(retcode), furl)\n\t\treturn false, err\n\t}\n\treturn true, err\n}\n"
  },
  {
    "path": "modules/agent/g/cfg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/toolkits/file\"\n)\n\ntype PluginConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tDir     string `json:\"dir\"`\n\tGit     string `json:\"git\"`\n\tLogDir  string `json:\"logs\"`\n}\n\ntype HeartbeatConfig struct {\n\tEnabled  bool   `json:\"enabled\"`\n\tAddr     string `json:\"addr\"`\n\tInterval int    `json:\"interval\"`\n\tTimeout  int    `json:\"timeout\"`\n}\n\ntype TransferConfig struct {\n\tEnabled  bool     `json:\"enabled\"`\n\tAddrs    []string `json:\"addrs\"`\n\tInterval int      `json:\"interval\"`\n\tTimeout  int      `json:\"timeout\"`\n}\n\ntype HttpConfig struct {\n\tEnabled  bool   `json:\"enabled\"`\n\tListen   string `json:\"listen\"`\n\tBackdoor bool   `json:\"backdoor\"`\n}\n\ntype CollectorConfig struct {\n\tIfacePrefix []string `json:\"ifacePrefix\"`\n\tMountPoint  []string `json:\"mountPoint\"`\n}\n\ntype GlobalConfig struct {\n\tDebug         bool              `json:\"debug\"`\n\tHostname      string            `json:\"hostname\"`\n\tIP            string            `json:\"ip\"`\n\tPlugin        *PluginConfig     `json:\"plugin\"`\n\tHeartbeat     *HeartbeatConfig  `json:\"heartbeat\"`\n\tTransfer      *TransferConfig   `json:\"transfer\"`\n\tHttp          *HttpConfig       `json:\"http\"`\n\tCollector     *CollectorConfig  `json:\"collector\"`\n\tDefaultTags   map[string]string `json:\"default_tags\"`\n\tIgnoreMetrics map[string]bool   `json:\"ignore\"`\n}\n\nvar (\n\tConfigFile string\n\tconfig     *GlobalConfig\n\tlock       = new(sync.RWMutex)\n)\n\nfunc Config() *GlobalConfig {\n\tlock.RLock()\n\tdefer lock.RUnlock()\n\treturn config\n}\n\nfunc Hostname() (string, error) {\n\thostname := Config().Hostname\n\tif hostname != \"\" {\n\t\treturn hostname, nil\n\t}\n\n\tif os.Getenv(\"FALCON_ENDPOINT\") != \"\" {\n\t\thostname = os.Getenv(\"FALCON_ENDPOINT\")\n\t\treturn hostname, nil\n\t}\n\n\thostname, err := os.Hostname()\n\tif err != nil {\n\t\tlog.Println(\"ERROR: os.Hostname() fail\", err)\n\t}\n\treturn hostname, err\n}\n\nfunc IP() string {\n\tip := Config().IP\n\tif ip != \"\" {\n\t\t// use ip in configuration\n\t\treturn ip\n\t}\n\n\tif len(LocalIp) > 0 {\n\t\tip = LocalIp\n\t}\n\n\treturn ip\n}\n\nfunc ParseConfig(cfg string) {\n\tif cfg == \"\" {\n\t\tlog.Fatalln(\"use -c to specify configuration file\")\n\t}\n\n\tif !file.IsExist(cfg) {\n\t\tlog.Fatalln(\"config file:\", cfg, \"is not existent. maybe you need `mv cfg.example.json cfg.json`\")\n\t}\n\n\tConfigFile = cfg\n\n\tconfigContent, err := file.ToTrimString(cfg)\n\tif err != nil {\n\t\tlog.Fatalln(\"read config file:\", cfg, \"fail:\", err)\n\t}\n\n\tvar c GlobalConfig\n\terr = json.Unmarshal([]byte(configContent), &c)\n\tif err != nil {\n\t\tlog.Fatalln(\"parse config file:\", cfg, \"fail:\", err)\n\t}\n\n\tlock.Lock()\n\tdefer lock.Unlock()\n\n\tconfig = &c\n\n\tlog.Println(\"read config file:\", cfg, \"successfully\")\n}\n"
  },
  {
    "path": "modules/agent/g/const.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"time\"\n)\n\n// changelog:\n// 3.1.3: code refactor\n// 3.1.4: bugfix ignore configuration\n// 5.0.0: 支持通过配置控制是否开启/run接口；收集udp流量数据；du某个目录的大小\n// 5.1.0: 同步插件的时候不再使用checksum机制\n// 5.1.1: 修复往多个transfer发送数据的时候crash的问题\n// 5.1.2: ignore mount point when blocks=0\n\nvar (\n\tBinaryName string\n\tVersion    string\n\tGitCommit  string\n)\n\nfunc VersionMsg() string {\n\treturn Version + \"@\" + GitCommit\n}\n\nconst (\n\tCOLLECT_INTERVAL = time.Second\n\tURL_CHECK_HEALTH = \"url.check.health\"\n\tNET_PORT_LISTEN  = \"net.port.listen\"\n\tDU_BS            = \"du.bs\"\n\tPROC_NUM         = \"proc.num\"\n)\n"
  },
  {
    "path": "modules/agent/g/g.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"runtime\"\n)\n\nfunc init() {\n\truntime.GOMAXPROCS(runtime.NumCPU())\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)\n}\n"
  },
  {
    "path": "modules/agent/g/logger.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport log \"github.com/sirupsen/logrus\"\n\nfunc InitLog(level string) (err error) {\n\tswitch level {\n\tcase \"info\":\n\t\tlog.SetLevel(log.InfoLevel)\n\tcase \"debug\":\n\t\tlog.SetLevel(log.DebugLevel)\n\tcase \"warn\":\n\t\tlog.SetLevel(log.WarnLevel)\n\tdefault:\n\t\tlog.Fatal(\"log conf only allow [info, debug, warn], please check your confguire\")\n\t}\n\treturn\n}\n"
  },
  {
    "path": "modules/agent/g/rpc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"errors\"\n\t\"github.com/toolkits/net\"\n\t\"log\"\n\t\"math\"\n\t\"net/rpc\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype SingleConnRpcClient struct {\n\tsync.Mutex\n\trpcClient *rpc.Client\n\tRpcServer string\n\tTimeout   time.Duration\n}\n\nfunc (this *SingleConnRpcClient) close() {\n\tif this.rpcClient != nil {\n\t\tthis.rpcClient.Close()\n\t\tthis.rpcClient = nil\n\t}\n}\n\nfunc (this *SingleConnRpcClient) serverConn() error {\n\tif this.rpcClient != nil {\n\t\treturn nil\n\t}\n\n\tvar err error\n\tvar retry int = 1\n\n\tfor {\n\t\tif this.rpcClient != nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tthis.rpcClient, err = net.JsonRpcClient(\"tcp\", this.RpcServer, this.Timeout)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"dial %s fail: %v\", this.RpcServer, err)\n\t\t\tif retry > 3 {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttime.Sleep(time.Duration(math.Pow(2.0, float64(retry))) * time.Second)\n\t\t\tretry++\n\t\t\tcontinue\n\t\t}\n\t\treturn err\n\t}\n}\n\nfunc (this *SingleConnRpcClient) Call(method string, args interface{}, reply interface{}) error {\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\terr := this.serverConn()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttimeout := time.Duration(10 * time.Second)\n\tdone := make(chan error, 1)\n\n\tgo func() {\n\t\terr := this.rpcClient.Call(method, args, reply)\n\t\tdone <- err\n\t}()\n\n\tselect {\n\tcase <-time.After(timeout):\n\t\tlog.Printf(\"[WARN] rpc call timeout %v => %v\", this.rpcClient, this.RpcServer)\n\t\tthis.close()\n\t\treturn errors.New(this.RpcServer + \" rpc call timeout\")\n\tcase err := <-done:\n\t\tif err != nil {\n\t\t\tthis.close()\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "modules/agent/g/tool.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"github.com/toolkits/file\"\n\t\"os/exec\"\n\t\"strings\"\n)\n\nfunc GetCurrPluginVersion() string {\n\tif !Config().Plugin.Enabled {\n\t\treturn \"plugin not enabled\"\n\t}\n\n\tpluginDir := Config().Plugin.Dir\n\tif !file.IsExist(pluginDir) {\n\t\treturn \"plugin dir not existent\"\n\t}\n\n\tcmd := exec.Command(\"git\", \"rev-parse\", \"HEAD\")\n\tcmd.Dir = pluginDir\n\n\tvar out bytes.Buffer\n\tcmd.Stdout = &out\n\terr := cmd.Run()\n\tif err != nil {\n\t\treturn fmt.Sprintf(\"Error:%s\", err.Error())\n\t}\n\n\treturn strings.TrimSpace(out.String())\n}\n"
  },
  {
    "path": "modules/agent/g/transfer.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n)\n\nvar (\n\tTransferClientsLock *sync.RWMutex                   = new(sync.RWMutex)\n\tTransferClients     map[string]*SingleConnRpcClient = map[string]*SingleConnRpcClient{}\n)\n\nfunc SendMetrics(metrics []*model.MetricValue, resp *model.TransferResponse) {\n\trand.Seed(time.Now().UnixNano())\n\tfor _, i := range rand.Perm(len(Config().Transfer.Addrs)) {\n\t\taddr := Config().Transfer.Addrs[i]\n\n\t\tc := getTransferClient(addr)\n\t\tif c == nil {\n\t\t\tc = initTransferClient(addr)\n\t\t}\n\n\t\tif updateMetrics(c, metrics, resp) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc initTransferClient(addr string) *SingleConnRpcClient {\n\tvar c *SingleConnRpcClient = &SingleConnRpcClient{\n\t\tRpcServer: addr,\n\t\tTimeout:   time.Duration(Config().Transfer.Timeout) * time.Millisecond,\n\t}\n\tTransferClientsLock.Lock()\n\tdefer TransferClientsLock.Unlock()\n\tTransferClients[addr] = c\n\n\treturn c\n}\n\nfunc updateMetrics(c *SingleConnRpcClient, metrics []*model.MetricValue, resp *model.TransferResponse) bool {\n\terr := c.Call(\"Transfer.Update\", metrics, resp)\n\tif err != nil {\n\t\tlog.Println(\"call Transfer.Update fail:\", c, err)\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc getTransferClient(addr string) *SingleConnRpcClient {\n\tTransferClientsLock.RLock()\n\tdefer TransferClientsLock.RUnlock()\n\n\tif c, ok := TransferClients[addr]; ok {\n\t\treturn c\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "modules/agent/g/var.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/slice\"\n)\n\nvar Root string\n\nfunc InitRootDir() {\n\tdefer func() {\n\t\tlog.Printf(\"Root dir: %s\", Root)\n\t}()\n\n\tpwd, err := os.Getwd()\n\tif err != nil {\n\t\tlog.Fatalln(\"getwd fail:\", err)\n\t}\n\tif root := lookupRootDir(pwd); root != \"\" {\n\t\tRoot = root\n\t\treturn\n\t}\n\tfile, _ := exec.LookPath(os.Args[0])\n\texecDir, _ := filepath.Abs(file)\n\tif root := lookupRootDir(path.Dir(execDir)); root != \"\" {\n\t\tRoot = root\n\t\treturn\n\t}\n\tRoot = pwd\n}\n\n// path目录下找 public，判断是否存在，不存在上级目录找\nfunc lookupRootDir(dir string) string {\n\tindex := filepath.Join(\"public\", \"index.html\")\n\tpublic := filepath.Join(dir, index)\n\tif _, err := os.Stat(public); os.IsNotExist(err) {\n\t\tfor i := 0; i < 2; i++ {\n\t\t\tparent := path.Dir(dir)\n\t\t\tpublic = filepath.Join(parent, index)\n\t\t\tif _, err := os.Stat(public); err == nil {\n\t\t\t\treturn parent\n\t\t\t}\n\t\t\tdir = parent\n\t\t}\n\t} else if err == nil {\n\t\treturn dir\n\t}\n\treturn \"\"\n}\n\nvar LocalIp string\n\nfunc InitLocalIp() {\n\tif Config().Heartbeat.Enabled {\n\t\tconn, err := net.DialTimeout(\"tcp\", Config().Heartbeat.Addr, time.Second*10)\n\t\tif err != nil {\n\t\t\tlog.Println(\"get local addr failed !\")\n\t\t} else {\n\t\t\tLocalIp = strings.Split(conn.LocalAddr().String(), \":\")[0]\n\t\t\tconn.Close()\n\t\t}\n\t} else {\n\t\tlog.Println(\"hearbeat is not enabled, can't get localip\")\n\t}\n}\n\nvar (\n\tHbsClient *SingleConnRpcClient\n)\n\nfunc InitRpcClients() {\n\tif Config().Heartbeat.Enabled {\n\t\tHbsClient = &SingleConnRpcClient{\n\t\t\tRpcServer: Config().Heartbeat.Addr,\n\t\t\tTimeout:   time.Duration(Config().Heartbeat.Timeout) * time.Millisecond,\n\t\t}\n\t}\n}\n\nfunc SendToTransfer(metrics []*model.MetricValue) {\n\tif len(metrics) == 0 {\n\t\treturn\n\t}\n\n\tdt := Config().DefaultTags\n\tif len(dt) > 0 {\n\t\tvar buf bytes.Buffer\n\t\tdefault_tags_list := []string{}\n\t\tfor k, v := range dt {\n\t\t\tbuf.Reset()\n\t\t\tbuf.WriteString(k)\n\t\t\tbuf.WriteString(\"=\")\n\t\t\tbuf.WriteString(v)\n\t\t\tdefault_tags_list = append(default_tags_list, buf.String())\n\t\t}\n\t\tdefault_tags := strings.Join(default_tags_list, \",\")\n\n\t\tfor i, x := range metrics {\n\t\t\tbuf.Reset()\n\t\t\tif x.Tags == \"\" {\n\t\t\t\tmetrics[i].Tags = default_tags\n\t\t\t} else {\n\t\t\t\tbuf.WriteString(metrics[i].Tags)\n\t\t\t\tbuf.WriteString(\",\")\n\t\t\t\tbuf.WriteString(default_tags)\n\t\t\t\tmetrics[i].Tags = buf.String()\n\t\t\t}\n\t\t}\n\t}\n\n\tdebug := Config().Debug\n\n\tif debug {\n\t\tlog.Printf(\"=> <Total=%d> %v\\n\", len(metrics), metrics[0])\n\t}\n\n\tvar resp model.TransferResponse\n\tSendMetrics(metrics, &resp)\n\n\tif debug {\n\t\tlog.Println(\"<=\", &resp)\n\t}\n}\n\nvar (\n\treportUrls     map[string]string\n\treportUrlsLock = new(sync.RWMutex)\n)\n\nfunc ReportUrls() map[string]string {\n\treportUrlsLock.RLock()\n\tdefer reportUrlsLock.RUnlock()\n\treturn reportUrls\n}\n\nfunc SetReportUrls(urls map[string]string) {\n\treportUrlsLock.RLock()\n\tdefer reportUrlsLock.RUnlock()\n\treportUrls = urls\n}\n\nvar (\n\treportPorts     []int64\n\treportPortsLock = new(sync.RWMutex)\n)\n\nfunc ReportPorts() []int64 {\n\treportPortsLock.RLock()\n\tdefer reportPortsLock.RUnlock()\n\treturn reportPorts\n}\n\nfunc SetReportPorts(ports []int64) {\n\treportPortsLock.Lock()\n\tdefer reportPortsLock.Unlock()\n\treportPorts = ports\n}\n\nvar (\n\tduPaths     []string\n\tduPathsLock = new(sync.RWMutex)\n)\n\nfunc DuPaths() []string {\n\tduPathsLock.RLock()\n\tdefer duPathsLock.RUnlock()\n\treturn duPaths\n}\n\nfunc SetDuPaths(paths []string) {\n\tduPathsLock.Lock()\n\tdefer duPathsLock.Unlock()\n\tduPaths = paths\n}\n\nvar (\n\t// tags => {1=>name, 2=>cmdline}\n\t// e.g. 'name=falcon-agent'=>{1=>falcon-agent}\n\t// e.g. 'cmdline=xx'=>{2=>xx}\n\treportProcs     map[string]map[int]string\n\treportProcsLock = new(sync.RWMutex)\n)\n\nfunc ReportProcs() map[string]map[int]string {\n\treportProcsLock.RLock()\n\tdefer reportProcsLock.RUnlock()\n\treturn reportProcs\n}\n\nfunc SetReportProcs(procs map[string]map[int]string) {\n\treportProcsLock.Lock()\n\tdefer reportProcsLock.Unlock()\n\treportProcs = procs\n}\n\nvar (\n\tips     []string\n\tipsLock = new(sync.Mutex)\n)\n\nfunc TrustableIps() []string {\n\tipsLock.Lock()\n\tdefer ipsLock.Unlock()\n\treturn ips\n}\n\nfunc SetTrustableIps(ipStr string) {\n\tarr := strings.Split(ipStr, \",\")\n\tipsLock.Lock()\n\tdefer ipsLock.Unlock()\n\tips = arr\n}\n\nfunc IsTrustable(remoteAddr string) bool {\n\tip := remoteAddr\n\tidx := strings.LastIndex(remoteAddr, \":\")\n\tif idx > 0 {\n\t\tip = remoteAddr[0:idx]\n\t}\n\n\tif ip == \"127.0.0.1\" {\n\t\treturn true\n\t}\n\n\treturn slice.ContainsString(TrustableIps(), ip)\n}\n"
  },
  {
    "path": "modules/agent/g/var_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n)\n\nfunc TestInitRootDir(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t}{\n\t\t{},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tInitRootDir()\n\t\t\tif getCurrentPath() != Root {\n\t\t\t\tt.Errorf(\"Root: [%v], actually: [%v]\", getCurrentPath(), Root)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc getCurrentPath() string {\n\t_, filename, _, _ := runtime.Caller(1)\n\treturn filepath.Dir(filepath.Dir(filename))\n}\n"
  },
  {
    "path": "modules/agent/http/admin.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/file\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n)\n\nfunc configAdminRoutes() {\n\thttp.HandleFunc(\"/exit\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif g.IsTrustable(r.RemoteAddr) {\n\t\t\tw.Write([]byte(\"exiting...\"))\n\t\t\tgo func() {\n\t\t\t\ttime.Sleep(time.Second)\n\t\t\t\tos.Exit(0)\n\t\t\t}()\n\t\t} else {\n\t\t\tw.Write([]byte(\"no privilege\"))\n\t\t}\n\t})\n\n\thttp.HandleFunc(\"/config/reload\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif g.IsTrustable(r.RemoteAddr) {\n\t\t\tg.ParseConfig(g.ConfigFile)\n\t\t\tRenderDataJson(w, g.Config())\n\t\t} else {\n\t\t\tw.Write([]byte(\"no privilege\"))\n\t\t}\n\t})\n\n\thttp.HandleFunc(\"/workdir\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, file.SelfDir())\n\t})\n\n\thttp.HandleFunc(\"/ips\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, g.TrustableIps())\n\t})\n}\n"
  },
  {
    "path": "modules/agent/http/cpu.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/funcs\"\n\t\"github.com/toolkits/nux\"\n\t\"net/http\"\n\t\"runtime\"\n)\n\nfunc configCpuRoutes() {\n\thttp.HandleFunc(\"/proc/cpu/num\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, runtime.NumCPU())\n\t})\n\n\thttp.HandleFunc(\"/proc/cpu/mhz\", func(w http.ResponseWriter, r *http.Request) {\n\t\tdata, err := nux.CpuMHz()\n\t\tAutoRender(w, data, err)\n\t})\n\n\thttp.HandleFunc(\"/page/cpu/usage\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif !funcs.CpuPrepared() {\n\t\t\tRenderMsgJson(w, \"not prepared\")\n\t\t\treturn\n\t\t}\n\n\t\tidle := funcs.CpuIdle()\n\t\tbusy := 100.0 - idle\n\n\t\titem := [10]string{\n\t\t\tfmt.Sprintf(\"%.1f%%\", idle),\n\t\t\tfmt.Sprintf(\"%.1f%%\", busy),\n\t\t\tfmt.Sprintf(\"%.1f%%\", funcs.CpuUser()),\n\t\t\tfmt.Sprintf(\"%.1f%%\", funcs.CpuNice()),\n\t\t\tfmt.Sprintf(\"%.1f%%\", funcs.CpuSystem()),\n\t\t\tfmt.Sprintf(\"%.1f%%\", funcs.CpuIowait()),\n\t\t\tfmt.Sprintf(\"%.1f%%\", funcs.CpuIrq()),\n\t\t\tfmt.Sprintf(\"%.1f%%\", funcs.CpuSoftIrq()),\n\t\t\tfmt.Sprintf(\"%.1f%%\", funcs.CpuSteal()),\n\t\t\tfmt.Sprintf(\"%.1f%%\", funcs.CpuGuest()),\n\t\t}\n\n\t\tRenderDataJson(w, [][10]string{item})\n\t})\n\n\thttp.HandleFunc(\"/proc/cpu/usage\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif !funcs.CpuPrepared() {\n\t\t\tRenderMsgJson(w, \"not prepared\")\n\t\t\treturn\n\t\t}\n\n\t\tidle := funcs.CpuIdle()\n\t\tbusy := 100.0 - idle\n\n\t\tRenderDataJson(w, map[string]interface{}{\n\t\t\t\"idle\":    idle,\n\t\t\t\"busy\":    busy,\n\t\t\t\"user\":    funcs.CpuUser(),\n\t\t\t\"nice\":    funcs.CpuNice(),\n\t\t\t\"system\":  funcs.CpuSystem(),\n\t\t\t\"iowait\":  funcs.CpuIowait(),\n\t\t\t\"irq\":     funcs.CpuIrq(),\n\t\t\t\"softirq\": funcs.CpuSoftIrq(),\n\t\t\t\"steal\":   funcs.CpuSteal(),\n\t\t\t\"guest\":   funcs.CpuGuest(),\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "modules/agent/http/df.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"fmt\"\n\t\"github.com/toolkits/core\"\n\t\"github.com/toolkits/nux\"\n\t\"net/http\"\n)\n\nfunc configDfRoutes() {\n\thttp.HandleFunc(\"/page/df\", func(w http.ResponseWriter, r *http.Request) {\n\t\tmountPoints, err := nux.ListMountPoint()\n\t\tif err != nil {\n\t\t\tRenderMsgJson(w, err.Error())\n\t\t\treturn\n\t\t}\n\n\t\tvar ret [][]interface{} = make([][]interface{}, 0)\n\t\tfor idx := range mountPoints {\n\t\t\tvar du *nux.DeviceUsage\n\t\t\tdu, err = nux.BuildDeviceUsage(mountPoints[idx][0], mountPoints[idx][1], mountPoints[idx][2])\n\t\t\tif err == nil {\n\t\t\t\tret = append(ret,\n\t\t\t\t\t[]interface{}{\n\t\t\t\t\t\tdu.FsSpec,\n\t\t\t\t\t\tcore.ReadableSize(float64(du.BlocksAll)),\n\t\t\t\t\t\tcore.ReadableSize(float64(du.BlocksUsed)),\n\t\t\t\t\t\tcore.ReadableSize(float64(du.BlocksFree)),\n\t\t\t\t\t\tfmt.Sprintf(\"%.1f%%\", du.BlocksUsedPercent),\n\t\t\t\t\t\tdu.FsFile,\n\t\t\t\t\t\tcore.ReadableSize(float64(du.InodesAll)),\n\t\t\t\t\t\tcore.ReadableSize(float64(du.InodesUsed)),\n\t\t\t\t\t\tcore.ReadableSize(float64(du.InodesFree)),\n\t\t\t\t\t\tfmt.Sprintf(\"%.1f%%\", du.InodesUsedPercent),\n\t\t\t\t\t\tdu.FsVfstype,\n\t\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tRenderDataJson(w, ret)\n\t})\n}\n"
  },
  {
    "path": "modules/agent/http/health.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"net/http\"\n)\n\nfunc configHealthRoutes() {\n\thttp.HandleFunc(\"/health\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"ok\"))\n\t})\n\n\thttp.HandleFunc(\"/version\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(g.VersionMsg()))\n\t})\n}\n"
  },
  {
    "path": "modules/agent/http/http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"log\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n)\n\ntype Dto struct {\n\tMsg  string      `json:\"msg\"`\n\tData interface{} `json:\"data\"`\n}\n\nfunc init() {\n\tconfigAdminRoutes()\n\tconfigCpuRoutes()\n\tconfigDfRoutes()\n\tconfigHealthRoutes()\n\tconfigIoStatRoutes()\n\tconfigKernelRoutes()\n\tconfigMemoryRoutes()\n\tconfigPageRoutes()\n\tconfigPluginRoutes()\n\tconfigPushRoutes()\n\tconfigRunRoutes()\n\tconfigSystemRoutes()\n}\n\nfunc RenderJson(w http.ResponseWriter, v interface{}) {\n\tbs, err := json.Marshal(v)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\tw.Write(bs)\n}\n\nfunc RenderDataJson(w http.ResponseWriter, data interface{}) {\n\tRenderJson(w, Dto{Msg: \"success\", Data: data})\n}\n\nfunc RenderMsgJson(w http.ResponseWriter, msg string) {\n\tRenderJson(w, map[string]string{\"msg\": msg})\n}\n\nfunc AutoRender(w http.ResponseWriter, data interface{}, err error) {\n\tif err != nil {\n\t\tRenderMsgJson(w, err.Error())\n\t\treturn\n\t}\n\n\tRenderDataJson(w, data)\n}\n\nfunc Start() {\n\tif !g.Config().Http.Enabled {\n\t\treturn\n\t}\n\n\taddr := g.Config().Http.Listen\n\tif addr == \"\" {\n\t\treturn\n\t}\n\n\ts := &http.Server{\n\t\tAddr:           addr,\n\t\tMaxHeaderBytes: 1 << 30,\n\t}\n\n\tlog.Println(\"listening\", addr)\n\tlog.Fatalln(s.ListenAndServe())\n}\n"
  },
  {
    "path": "modules/agent/http/iostat.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/agent/funcs\"\n\t\"net/http\"\n)\n\nfunc configIoStatRoutes() {\n\thttp.HandleFunc(\"/page/diskio\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, funcs.IOStatsForPage())\n\t})\n}\n"
  },
  {
    "path": "modules/agent/http/kernel.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/nux\"\n\t\"github.com/toolkits/sys\"\n\t\"net/http\"\n)\n\nfunc configKernelRoutes() {\n\thttp.HandleFunc(\"/proc/kernel/hostname\", func(w http.ResponseWriter, r *http.Request) {\n\t\tdata, err := g.Hostname()\n\t\tAutoRender(w, data, err)\n\t})\n\n\thttp.HandleFunc(\"/proc/kernel/maxproc\", func(w http.ResponseWriter, r *http.Request) {\n\t\tdata, err := nux.KernelMaxProc()\n\t\tAutoRender(w, data, err)\n\t})\n\n\thttp.HandleFunc(\"/proc/kernel/maxfiles\", func(w http.ResponseWriter, r *http.Request) {\n\t\tdata, err := nux.KernelMaxFiles()\n\t\tAutoRender(w, data, err)\n\t})\n\n\thttp.HandleFunc(\"/proc/kernel/version\", func(w http.ResponseWriter, r *http.Request) {\n\t\tdata, err := sys.CmdOutNoLn(\"uname\", \"-r\")\n\t\tAutoRender(w, data, err)\n\t})\n\n}\n"
  },
  {
    "path": "modules/agent/http/memory.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/toolkits/nux\"\n\t\"net/http\"\n)\n\nfunc configMemoryRoutes() {\n\thttp.HandleFunc(\"/page/memory\", func(w http.ResponseWriter, r *http.Request) {\n\t\tmem, err := nux.MemInfo()\n\t\tif err != nil {\n\t\t\tRenderMsgJson(w, err.Error())\n\t\t\treturn\n\t\t}\n\n\t\tmemFree := mem.MemFree + mem.Buffers + mem.Cached\n\t\tmemUsed := mem.MemTotal - memFree\n\t\tvar t uint64 = 1024 * 1024\n\t\tRenderDataJson(w, []interface{}{mem.MemTotal / t, memUsed / t, memFree / t})\n\t})\n\n\thttp.HandleFunc(\"/proc/memory\", func(w http.ResponseWriter, r *http.Request) {\n\t\tmem, err := nux.MemInfo()\n\t\tif err != nil {\n\t\t\tRenderMsgJson(w, err.Error())\n\t\t\treturn\n\t\t}\n\n\t\tmemFree := mem.MemFree + mem.Buffers + mem.Cached\n\t\tmemUsed := mem.MemTotal - memFree\n\n\t\tRenderDataJson(w, map[string]interface{}{\n\t\t\t\"total\": mem.MemTotal,\n\t\t\t\"free\":  memFree,\n\t\t\t\"used\":  memUsed,\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "modules/agent/http/page.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/file\"\n\t\"net/http\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nfunc configPageRoutes() {\n\n\thttp.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif strings.HasSuffix(r.URL.Path, \"/\") {\n\t\t\tif !file.IsExist(filepath.Join(g.Root, \"/public\", r.URL.Path, \"index.html\")) {\n\t\t\t\thttp.NotFound(w, r)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\thttp.FileServer(http.Dir(filepath.Join(g.Root, \"/public\"))).ServeHTTP(w, r)\n\t})\n\n}\n"
  },
  {
    "path": "modules/agent/http/plugin.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/plugins\"\n\t\"github.com/toolkits/file\"\n\t\"net/http\"\n\t\"os/exec\"\n)\n\nfunc configPluginRoutes() {\n\thttp.HandleFunc(\"/plugin/update\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif !g.Config().Plugin.Enabled {\n\t\t\tw.Write([]byte(\"plugin not enabled\"))\n\t\t\treturn\n\t\t}\n\n\t\tdir := g.Config().Plugin.Dir\n\t\tparentDir := file.Dir(dir)\n\t\tfile.InsureDir(parentDir)\n\n\t\tif file.IsExist(dir) {\n\t\t\t// git pull\n\t\t\tcmd := exec.Command(\"git\", \"pull\")\n\t\t\tcmd.Dir = dir\n\t\t\terr := cmd.Run()\n\t\t\tif err != nil {\n\t\t\t\tw.Write([]byte(fmt.Sprintf(\"git pull in dir:%s fail. error: %s\", dir, err)))\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\t// git clone\n\t\t\tcmd := exec.Command(\"git\", \"clone\", g.Config().Plugin.Git, file.Basename(dir))\n\t\t\tcmd.Dir = parentDir\n\t\t\terr := cmd.Run()\n\t\t\tif err != nil {\n\t\t\t\tw.Write([]byte(fmt.Sprintf(\"git clone in dir:%s fail. error: %s\", parentDir, err)))\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tw.Write([]byte(\"success\"))\n\t})\n\n\thttp.HandleFunc(\"/plugin/reset\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif !g.Config().Plugin.Enabled {\n\t\t\tw.Write([]byte(\"plugin not enabled\"))\n\t\t\treturn\n\t\t}\n\n\t\tdir := g.Config().Plugin.Dir\n\n\t\tif file.IsExist(dir) {\n\t\t\tcmd := exec.Command(\"git\", \"reset\", \"--hard\")\n\t\t\tcmd.Dir = dir\n\t\t\terr := cmd.Run()\n\t\t\tif err != nil {\n\t\t\t\tw.Write([]byte(fmt.Sprintf(\"git reset --hard in dir:%s fail. error: %s\", dir, err)))\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tw.Write([]byte(\"success\"))\n\t})\n\n\thttp.HandleFunc(\"/plugins\", func(w http.ResponseWriter, r *http.Request) {\n\t\t//TODO: not thread safe\n\t\tRenderDataJson(w, plugins.Plugins)\n\t})\n}\n"
  },
  {
    "path": "modules/agent/http/push.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"net/http\"\n)\n\nfunc configPushRoutes() {\n\thttp.HandleFunc(\"/v1/push\", func(w http.ResponseWriter, req *http.Request) {\n\t\tif req.ContentLength == 0 {\n\t\t\thttp.Error(w, \"body is blank\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\n\t\tdecoder := json.NewDecoder(req.Body)\n\t\tvar metrics []*model.MetricValue\n\t\terr := decoder.Decode(&metrics)\n\t\tif err != nil {\n\t\t\thttp.Error(w, \"connot decode body\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\n\t\tg.SendToTransfer(metrics)\n\t\tw.Write([]byte(\"success\"))\n\t})\n}\n"
  },
  {
    "path": "modules/agent/http/run.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/sys\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc configRunRoutes() {\n\thttp.HandleFunc(\"/run\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif !g.Config().Http.Backdoor {\n\t\t\tw.Write([]byte(\"/run disabled\"))\n\t\t\treturn\n\t\t}\n\n\t\tif g.IsTrustable(r.RemoteAddr) {\n\t\t\tif r.ContentLength == 0 {\n\t\t\t\thttp.Error(w, \"body is blank\", http.StatusBadRequest)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tbs, err := ioutil.ReadAll(r.Body)\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tbody := string(bs)\n\t\t\tout, err := sys.CmdOutBytes(\"sh\", \"-c\", body)\n\t\t\tif err != nil {\n\t\t\t\tw.Write([]byte(\"exec fail: \" + err.Error()))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tw.Write(out)\n\t\t} else {\n\t\t\tw.Write([]byte(\"no privilege\"))\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "modules/agent/http/system.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"fmt\"\n\t\"github.com/toolkits/nux\"\n\t\"net/http\"\n\t\"runtime\"\n\t\"time\"\n)\n\nfunc configSystemRoutes() {\n\n\thttp.HandleFunc(\"/system/date\", func(w http.ResponseWriter, req *http.Request) {\n\t\tRenderDataJson(w, time.Now().Format(\"2006-01-02 15:04:05\"))\n\t})\n\n\thttp.HandleFunc(\"/page/system/uptime\", func(w http.ResponseWriter, req *http.Request) {\n\t\tdays, hours, mins, err := nux.SystemUptime()\n\t\tAutoRender(w, fmt.Sprintf(\"%d days %d hours %d minutes\", days, hours, mins), err)\n\t})\n\n\thttp.HandleFunc(\"/proc/system/uptime\", func(w http.ResponseWriter, req *http.Request) {\n\t\tdays, hours, mins, err := nux.SystemUptime()\n\t\tif err != nil {\n\t\t\tRenderMsgJson(w, err.Error())\n\t\t\treturn\n\t\t}\n\n\t\tRenderDataJson(w, map[string]interface{}{\n\t\t\t\"days\":  days,\n\t\t\t\"hours\": hours,\n\t\t\t\"mins\":  mins,\n\t\t})\n\t})\n\n\thttp.HandleFunc(\"/page/system/loadavg\", func(w http.ResponseWriter, req *http.Request) {\n\t\tcpuNum := runtime.NumCPU()\n\t\tload, err := nux.LoadAvg()\n\t\tif err != nil {\n\t\t\tRenderMsgJson(w, err.Error())\n\t\t\treturn\n\t\t}\n\n\t\tret := [3][2]interface{}{\n\t\t\t{load.Avg1min, int64(load.Avg1min * 100.0 / float64(cpuNum))},\n\t\t\t{load.Avg5min, int64(load.Avg5min * 100.0 / float64(cpuNum))},\n\t\t\t{load.Avg15min, int64(load.Avg15min * 100.0 / float64(cpuNum))},\n\t\t}\n\t\tRenderDataJson(w, ret)\n\t})\n\n\thttp.HandleFunc(\"/proc/system/loadavg\", func(w http.ResponseWriter, req *http.Request) {\n\t\tdata, err := nux.LoadAvg()\n\t\tAutoRender(w, data, err)\n\t})\n\n}\n"
  },
  {
    "path": "modules/agent/main.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/cron\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/funcs\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/http\"\n\t\"os\"\n)\n\nfunc main() {\n\n\tg.BinaryName = BinaryName\n\tg.Version = Version\n\tg.GitCommit = GitCommit\n\n\tcfg := flag.String(\"c\", \"cfg.json\", \"configuration file\")\n\tversion := flag.Bool(\"v\", false, \"show version\")\n\tcheck := flag.Bool(\"check\", false, \"check collector\")\n\n\tflag.Parse()\n\n\tif *version {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\n\tif *check {\n\t\tfuncs.CheckCollector()\n\t\tos.Exit(0)\n\t}\n\n\tg.ParseConfig(*cfg)\n\n\tif g.Config().Debug {\n\t\tg.InitLog(\"debug\")\n\t} else {\n\t\tg.InitLog(\"info\")\n\t}\n\n\tg.InitRootDir()\n\tg.InitLocalIp()\n\tg.InitRpcClients()\n\n\tfuncs.BuildMappers()\n\n\tgo cron.InitDataHistory()\n\n\tcron.ReportAgentStatus()\n\tcron.SyncMinePlugins()\n\tcron.SyncBuiltinMetrics()\n\tcron.SyncTrustableIps()\n\tcron.Collect()\n\n\tgo http.Start()\n\n\tselect {}\n\n}\n"
  },
  {
    "path": "modules/agent/plugins/plugins.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage plugins\n\ntype Plugin struct {\n\tFilePath string\n\tMTime    int64\n\tCycle    int\n\tArgs     string\n}\n\nvar (\n\tPlugins              = make(map[string]*Plugin)\n\tPluginsWithScheduler = make(map[string]*PluginScheduler)\n)\n\nfunc DelNoUsePlugins(newPlugins map[string]*Plugin) {\n\tfor currKey, currPlugin := range Plugins {\n\t\tnewPlugin, ok := newPlugins[currKey]\n\t\tif !ok || currPlugin.MTime != newPlugin.MTime {\n\t\t\tdeletePlugin(currKey)\n\t\t}\n\t}\n}\n\nfunc AddNewPlugins(newPlugins map[string]*Plugin) {\n\tfor fpath, newPlugin := range newPlugins {\n\t\tif _, ok := Plugins[fpath]; ok && newPlugin.MTime == Plugins[fpath].MTime {\n\t\t\tcontinue\n\t\t}\n\n\t\tPlugins[fpath] = newPlugin\n\t\tsch := NewPluginScheduler(newPlugin)\n\t\tPluginsWithScheduler[fpath] = sch\n\t\tsch.Schedule()\n\t}\n}\n\nfunc ClearAllPlugins() {\n\tfor k := range Plugins {\n\t\tdeletePlugin(k)\n\t}\n}\n\nfunc deletePlugin(key string) {\n\tv, ok := PluginsWithScheduler[key]\n\tif ok {\n\t\tv.Stop()\n\t\tdelete(PluginsWithScheduler, key)\n\t}\n\tdelete(Plugins, key)\n}\n"
  },
  {
    "path": "modules/agent/plugins/reader.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage plugins\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// return: dict{sys/ntp/60_ntp.py : *Plugin}\nfunc ListPlugins(script_path string) map[string]*Plugin {\n\tret := make(map[string]*Plugin)\n\tif script_path == \"\" {\n\t\treturn ret\n\t}\n\n\tabs_path := filepath.Join(g.Config().Plugin.Dir, script_path)\n\tfs, err := ioutil.ReadDir(abs_path)\n\tif err != nil {\n\t\tlog.Println(\"can not list files under\", abs_path)\n\t\treturn ret\n\t}\n\n\tfor _, f := range fs {\n\t\tif f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfilename := f.Name()\n\t\tarr := strings.Split(filename, \"_\")\n\t\tif len(arr) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// filename should be: $cycle_$xx\n\t\tvar cycle int\n\t\tcycle, err = strconv.Atoi(arr[0])\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfpath := filepath.Join(script_path, filename)\n\t\tplugin := &Plugin{FilePath: fpath, MTime: f.ModTime().Unix(), Cycle: cycle, Args: \"\"}\n\t\tret[fpath] = plugin\n\t}\n\treturn ret\n}\n"
  },
  {
    "path": "modules/agent/plugins/scheduler.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage plugins\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"log\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/agent/g\"\n\t\"github.com/toolkits/file\"\n\t\"github.com/toolkits/sys\"\n)\n\ntype PluginScheduler struct {\n\tTicker *time.Ticker\n\tPlugin *Plugin\n\tQuit   chan struct{}\n}\n\nfunc NewPluginScheduler(p *Plugin) *PluginScheduler {\n\tscheduler := PluginScheduler{Plugin: p}\n\tscheduler.Ticker = time.NewTicker(time.Duration(p.Cycle) * time.Second)\n\tscheduler.Quit = make(chan struct{})\n\treturn &scheduler\n}\n\nfunc (this *PluginScheduler) Schedule() {\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-this.Ticker.C:\n\t\t\t\tPluginRun(this.Plugin)\n\t\t\tcase <-this.Quit:\n\t\t\t\tthis.Ticker.Stop()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n}\n\nfunc (this *PluginScheduler) Stop() {\n\tclose(this.Quit)\n}\n\n// using ',' as the seprator of args and '\\,' to espace\nfunc PluginArgsParse(raw_args string) []string {\n\tss := strings.Split(raw_args, \"\\\\,\")\n\n\tout := [][]string{}\n\tfor _, s := range ss {\n\t\tclean_args := []string{}\n\t\tfor _, arg := range strings.Split(s, \",\") {\n\t\t\targ = strings.Trim(arg, \" \")\n\t\t\targ = strings.Trim(arg, \"\\\"\")\n\t\t\targ = strings.Trim(arg, \"'\")\n\t\t\tclean_args = append(clean_args, arg)\n\t\t}\n\t\tout = append(out, clean_args)\n\t}\n\n\tret := []string{}\n\ttail := \"\"\n\n\tfor _, x := range out {\n\t\tfor j, y := range x {\n\t\t\tif j == 0 {\n\t\t\t\tif tail != \"\" {\n\t\t\t\t\tret = append(ret, tail+\",\"+y)\n\t\t\t\t\ttail = \"\"\n\t\t\t\t} else {\n\t\t\t\t\tret = append(ret, y)\n\t\t\t\t}\n\t\t\t} else if j == len(x)-1 {\n\t\t\t\ttail = y\n\t\t\t} else {\n\t\t\t\tret = append(ret, y)\n\t\t\t}\n\t\t}\n\t}\n\n\tif tail != \"\" {\n\t\tret = append(ret, tail)\n\t}\n\n\treturn ret\n}\n\nfunc PluginRun(plugin *Plugin) {\n\ttimeout := plugin.Cycle*1000 - 500\n\tfpath := filepath.Join(g.Config().Plugin.Dir, plugin.FilePath)\n\targs := plugin.Args\n\n\tif !file.IsExist(fpath) {\n\t\tlog.Printf(\"no such plugin: %s(%s)\", fpath, args)\n\t\treturn\n\t}\n\n\tdebug := g.Config().Debug\n\tif debug {\n\t\tlog.Printf(\"%s(%s) running...\", fpath, args)\n\t}\n\n\tvar cmd *exec.Cmd\n\tif args == \"\" {\n\t\tcmd = exec.Command(fpath)\n\t} else {\n\t\targ_list := PluginArgsParse(args)\n\t\tcmd = exec.Command(fpath, arg_list...)\n\t}\n\tvar stdout bytes.Buffer\n\tcmd.Stdout = &stdout\n\tvar stderr bytes.Buffer\n\tcmd.Stderr = &stderr\n\tcmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}\n\terr := cmd.Start()\n\tif err != nil {\n\t\tlog.Printf(\"[ERROR] plugin start fail: %s(%s) , error: %s\\n\", fpath, args, err)\n\t\treturn\n\t}\n\tif debug {\n\t\tlog.Printf(\"plugin started: %s(%s)\", fpath, args)\n\t}\n\n\terr, isTimeout := sys.CmdRunWithTimeout(cmd, time.Duration(timeout)*time.Millisecond)\n\n\terrStr := stderr.String()\n\tif errStr != \"\" {\n\t\tlogFile := filepath.Join(g.Config().Plugin.LogDir, plugin.FilePath+\"(\"+plugin.Args+\")\"+\".stderr.log\")\n\t\tif _, err = file.WriteString(logFile, errStr); err != nil {\n\t\t\tlog.Printf(\"[ERROR] write log to %s fail, error: %s\\n\", logFile, err)\n\t\t}\n\t}\n\n\tif isTimeout {\n\t\t// has be killed\n\t\tif err == nil && debug {\n\t\t\tlog.Println(\"[INFO] timeout and kill process \", fpath, \"(\", args, \")\", \" successfully\")\n\t\t}\n\n\t\tif err != nil {\n\t\t\tlog.Println(\"[ERROR] kill process \", fpath, \"(\", args, \")\", \" occur error:\", err)\n\t\t}\n\n\t\treturn\n\t}\n\n\tif err != nil {\n\t\tlog.Println(\"[ERROR] exec plugin\", fpath, \"(\", args, \")\", \"fail. error:\", err)\n\t\treturn\n\t}\n\n\t// exec successfully\n\tdata := stdout.Bytes()\n\tif len(data) == 0 {\n\t\tif debug {\n\t\t\tlog.Println(\"[DEBUG] stdout of\", fpath, \"(\", args, \")\", \"is blank\")\n\t\t}\n\t\treturn\n\t}\n\n\tvar metrics []*model.MetricValue\n\terr = json.Unmarshal(data, &metrics)\n\tif err != nil {\n\t\tlog.Printf(\"[ERROR] json.Unmarshal stdout of %s(%s) fail. error:%s stdout: \\n%s\\n\", fpath, args, err, stdout.String())\n\t\treturn\n\t}\n\n\tg.SendToTransfer(metrics)\n}\n"
  },
  {
    "path": "modules/agent/public/css/font-awesome/css/archive/font-awesome-ie7.css",
    "content": "/*!\n *  Font Awesome 3.2.1\n *  the iconic font designed for Bootstrap\n *  ------------------------------------------------------------------------------\n *  The full suite of pictographic icons, examples, and documentation can be\n *  found at http://fontawesome.io.  Stay up to date on Twitter at\n *  http://twitter.com/fontawesome.\n *\n *  License\n *  ------------------------------------------------------------------------------\n *  - The Font Awesome font is licensed under SIL OFL 1.1 -\n *    http://scripts.sil.org/OFL\n *  - Font Awesome CSS, LESS, and SASS files are licensed under MIT License -\n *    http://opensource.org/licenses/mit-license.html\n *  - Font Awesome documentation licensed under CC BY 3.0 -\n *    http://creativecommons.org/licenses/by/3.0/\n *  - Attribution is no longer required in Font Awesome 3.0, but much appreciated:\n *    \"Font Awesome by Dave Gandy - http://fontawesome.io\"\n *\n *  Author - Dave Gandy\n *  ------------------------------------------------------------------------------\n *  Email: dave@fontawesome.io\n *  Twitter: http://twitter.com/davegandy\n *  Work: Lead Product Designer @ Kyruus - http://kyruus.com\n */\n.icon-large {\n  font-size: 1.3333333333333333em;\n  margin-top: -4px;\n  padding-top: 3px;\n  margin-bottom: -4px;\n  padding-bottom: 3px;\n  vertical-align: middle;\n}\n.nav [class^=\"icon-\"],\n.nav [class*=\" icon-\"] {\n  vertical-align: inherit;\n  margin-top: -4px;\n  padding-top: 3px;\n  margin-bottom: -4px;\n  padding-bottom: 3px;\n}\n.nav [class^=\"icon-\"].icon-large,\n.nav [class*=\" icon-\"].icon-large {\n  vertical-align: -25%;\n}\n.nav-pills [class^=\"icon-\"].icon-large,\n.nav-tabs [class^=\"icon-\"].icon-large,\n.nav-pills [class*=\" icon-\"].icon-large,\n.nav-tabs [class*=\" icon-\"].icon-large {\n  line-height: .75em;\n  margin-top: -7px;\n  padding-top: 5px;\n  margin-bottom: -5px;\n  padding-bottom: 4px;\n}\n.btn [class^=\"icon-\"].pull-left,\n.btn [class*=\" icon-\"].pull-left,\n.btn [class^=\"icon-\"].pull-right,\n.btn [class*=\" icon-\"].pull-right {\n  vertical-align: inherit;\n}\n.btn [class^=\"icon-\"].icon-large,\n.btn [class*=\" icon-\"].icon-large {\n  margin-top: -0.5em;\n}\na [class^=\"icon-\"],\na [class*=\" icon-\"] {\n  cursor: pointer;\n}\n.icon-glass {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf000;');\n}\n.icon-music {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf001;');\n}\n.icon-search {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf002;');\n}\n.icon-envelope-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf003;');\n}\n.icon-heart {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf004;');\n}\n.icon-star {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf005;');\n}\n.icon-star-empty {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf006;');\n}\n.icon-user {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf007;');\n}\n.icon-film {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf008;');\n}\n.icon-th-large {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf009;');\n}\n.icon-th {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf00a;');\n}\n.icon-th-list {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf00b;');\n}\n.icon-ok {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf00c;');\n}\n.icon-remove {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf00d;');\n}\n.icon-zoom-in {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf00e;');\n}\n.icon-zoom-out {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf010;');\n}\n.icon-off {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf011;');\n}\n.icon-power-off {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf011;');\n}\n.icon-signal {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf012;');\n}\n.icon-cog {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf013;');\n}\n.icon-gear {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf013;');\n}\n.icon-trash {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf014;');\n}\n.icon-home {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf015;');\n}\n.icon-file-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf016;');\n}\n.icon-time {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf017;');\n}\n.icon-road {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf018;');\n}\n.icon-download-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf019;');\n}\n.icon-download {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf01a;');\n}\n.icon-upload {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf01b;');\n}\n.icon-inbox {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf01c;');\n}\n.icon-play-circle {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf01d;');\n}\n.icon-repeat {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf01e;');\n}\n.icon-rotate-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf01e;');\n}\n.icon-refresh {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf021;');\n}\n.icon-list-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf022;');\n}\n.icon-lock {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf023;');\n}\n.icon-flag {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf024;');\n}\n.icon-headphones {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf025;');\n}\n.icon-volume-off {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf026;');\n}\n.icon-volume-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf027;');\n}\n.icon-volume-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf028;');\n}\n.icon-qrcode {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf029;');\n}\n.icon-barcode {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf02a;');\n}\n.icon-tag {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf02b;');\n}\n.icon-tags {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf02c;');\n}\n.icon-book {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf02d;');\n}\n.icon-bookmark {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf02e;');\n}\n.icon-print {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf02f;');\n}\n.icon-camera {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf030;');\n}\n.icon-font {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf031;');\n}\n.icon-bold {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf032;');\n}\n.icon-italic {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf033;');\n}\n.icon-text-height {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf034;');\n}\n.icon-text-width {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf035;');\n}\n.icon-align-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf036;');\n}\n.icon-align-center {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf037;');\n}\n.icon-align-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf038;');\n}\n.icon-align-justify {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf039;');\n}\n.icon-list {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf03a;');\n}\n.icon-indent-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf03b;');\n}\n.icon-indent-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf03c;');\n}\n.icon-facetime-video {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf03d;');\n}\n.icon-picture {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf03e;');\n}\n.icon-pencil {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf040;');\n}\n.icon-map-marker {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf041;');\n}\n.icon-adjust {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf042;');\n}\n.icon-tint {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf043;');\n}\n.icon-edit {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf044;');\n}\n.icon-share {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf045;');\n}\n.icon-check {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf046;');\n}\n.icon-move {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf047;');\n}\n.icon-step-backward {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf048;');\n}\n.icon-fast-backward {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf049;');\n}\n.icon-backward {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf04a;');\n}\n.icon-play {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf04b;');\n}\n.icon-pause {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf04c;');\n}\n.icon-stop {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf04d;');\n}\n.icon-forward {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf04e;');\n}\n.icon-fast-forward {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf050;');\n}\n.icon-step-forward {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf051;');\n}\n.icon-eject {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf052;');\n}\n.icon-chevron-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf053;');\n}\n.icon-chevron-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf054;');\n}\n.icon-plus-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf055;');\n}\n.icon-minus-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf056;');\n}\n.icon-remove-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf057;');\n}\n.icon-ok-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf058;');\n}\n.icon-question-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf059;');\n}\n.icon-info-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf05a;');\n}\n.icon-screenshot {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf05b;');\n}\n.icon-remove-circle {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf05c;');\n}\n.icon-ok-circle {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf05d;');\n}\n.icon-ban-circle {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf05e;');\n}\n.icon-arrow-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf060;');\n}\n.icon-arrow-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf061;');\n}\n.icon-arrow-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf062;');\n}\n.icon-arrow-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf063;');\n}\n.icon-share-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf064;');\n}\n.icon-mail-forward {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf064;');\n}\n.icon-resize-full {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf065;');\n}\n.icon-resize-small {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf066;');\n}\n.icon-plus {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf067;');\n}\n.icon-minus {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf068;');\n}\n.icon-asterisk {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf069;');\n}\n.icon-exclamation-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf06a;');\n}\n.icon-gift {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf06b;');\n}\n.icon-leaf {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf06c;');\n}\n.icon-fire {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf06d;');\n}\n.icon-eye-open {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf06e;');\n}\n.icon-eye-close {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf070;');\n}\n.icon-warning-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf071;');\n}\n.icon-plane {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf072;');\n}\n.icon-calendar {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf073;');\n}\n.icon-random {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf074;');\n}\n.icon-comment {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf075;');\n}\n.icon-magnet {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf076;');\n}\n.icon-chevron-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf077;');\n}\n.icon-chevron-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf078;');\n}\n.icon-retweet {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf079;');\n}\n.icon-shopping-cart {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf07a;');\n}\n.icon-folder-close {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf07b;');\n}\n.icon-folder-open {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf07c;');\n}\n.icon-resize-vertical {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf07d;');\n}\n.icon-resize-horizontal {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf07e;');\n}\n.icon-bar-chart {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf080;');\n}\n.icon-twitter-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf081;');\n}\n.icon-facebook-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf082;');\n}\n.icon-camera-retro {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf083;');\n}\n.icon-key {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf084;');\n}\n.icon-cogs {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf085;');\n}\n.icon-gears {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf085;');\n}\n.icon-comments {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf086;');\n}\n.icon-thumbs-up-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf087;');\n}\n.icon-thumbs-down-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf088;');\n}\n.icon-star-half {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf089;');\n}\n.icon-heart-empty {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08a;');\n}\n.icon-signout {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08b;');\n}\n.icon-linkedin-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08c;');\n}\n.icon-pushpin {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08d;');\n}\n.icon-external-link {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08e;');\n}\n.icon-signin {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf090;');\n}\n.icon-trophy {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf091;');\n}\n.icon-github-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf092;');\n}\n.icon-upload-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf093;');\n}\n.icon-lemon {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf094;');\n}\n.icon-phone {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf095;');\n}\n.icon-check-empty {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf096;');\n}\n.icon-unchecked {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf096;');\n}\n.icon-bookmark-empty {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf097;');\n}\n.icon-phone-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf098;');\n}\n.icon-twitter {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf099;');\n}\n.icon-facebook {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09a;');\n}\n.icon-github {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09b;');\n}\n.icon-unlock {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09c;');\n}\n.icon-credit-card {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09d;');\n}\n.icon-rss {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09e;');\n}\n.icon-hdd {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a0;');\n}\n.icon-bullhorn {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a1;');\n}\n.icon-bell {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a2;');\n}\n.icon-certificate {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a3;');\n}\n.icon-hand-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a4;');\n}\n.icon-hand-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a5;');\n}\n.icon-hand-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a6;');\n}\n.icon-hand-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a7;');\n}\n.icon-circle-arrow-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a8;');\n}\n.icon-circle-arrow-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0a9;');\n}\n.icon-circle-arrow-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0aa;');\n}\n.icon-circle-arrow-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ab;');\n}\n.icon-globe {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ac;');\n}\n.icon-wrench {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ad;');\n}\n.icon-tasks {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ae;');\n}\n.icon-filter {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0b0;');\n}\n.icon-briefcase {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0b1;');\n}\n.icon-fullscreen {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0b2;');\n}\n.icon-group {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c0;');\n}\n.icon-link {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c1;');\n}\n.icon-cloud {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c2;');\n}\n.icon-beaker {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c3;');\n}\n.icon-cut {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c4;');\n}\n.icon-copy {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c5;');\n}\n.icon-paper-clip {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c6;');\n}\n.icon-paperclip {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c6;');\n}\n.icon-save {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c7;');\n}\n.icon-sign-blank {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c8;');\n}\n.icon-reorder {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c9;');\n}\n.icon-list-ul {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ca;');\n}\n.icon-list-ol {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0cb;');\n}\n.icon-strikethrough {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0cc;');\n}\n.icon-underline {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0cd;');\n}\n.icon-table {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ce;');\n}\n.icon-magic {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d0;');\n}\n.icon-truck {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d1;');\n}\n.icon-pinterest {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d2;');\n}\n.icon-pinterest-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d3;');\n}\n.icon-google-plus-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d4;');\n}\n.icon-google-plus {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d5;');\n}\n.icon-money {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d6;');\n}\n.icon-caret-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d7;');\n}\n.icon-caret-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d8;');\n}\n.icon-caret-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0d9;');\n}\n.icon-caret-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0da;');\n}\n.icon-columns {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0db;');\n}\n.icon-sort {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0dc;');\n}\n.icon-sort-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0dd;');\n}\n.icon-sort-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0de;');\n}\n.icon-envelope {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e0;');\n}\n.icon-linkedin {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e1;');\n}\n.icon-undo {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e2;');\n}\n.icon-rotate-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e2;');\n}\n.icon-legal {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e3;');\n}\n.icon-dashboard {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e4;');\n}\n.icon-comment-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e5;');\n}\n.icon-comments-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e6;');\n}\n.icon-bolt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e7;');\n}\n.icon-sitemap {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e8;');\n}\n.icon-umbrella {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e9;');\n}\n.icon-paste {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ea;');\n}\n.icon-lightbulb {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0eb;');\n}\n.icon-exchange {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ec;');\n}\n.icon-cloud-download {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ed;');\n}\n.icon-cloud-upload {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0ee;');\n}\n.icon-user-md {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f0;');\n}\n.icon-stethoscope {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f1;');\n}\n.icon-suitcase {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f2;');\n}\n.icon-bell-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f3;');\n}\n.icon-coffee {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f4;');\n}\n.icon-food {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f5;');\n}\n.icon-file-text-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f6;');\n}\n.icon-building {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f7;');\n}\n.icon-hospital {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f8;');\n}\n.icon-ambulance {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f9;');\n}\n.icon-medkit {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0fa;');\n}\n.icon-fighter-jet {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0fb;');\n}\n.icon-beer {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0fc;');\n}\n.icon-h-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0fd;');\n}\n.icon-plus-sign-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0fe;');\n}\n.icon-double-angle-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf100;');\n}\n.icon-double-angle-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf101;');\n}\n.icon-double-angle-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf102;');\n}\n.icon-double-angle-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf103;');\n}\n.icon-angle-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf104;');\n}\n.icon-angle-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf105;');\n}\n.icon-angle-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf106;');\n}\n.icon-angle-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf107;');\n}\n.icon-desktop {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf108;');\n}\n.icon-laptop {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf109;');\n}\n.icon-tablet {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf10a;');\n}\n.icon-mobile-phone {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf10b;');\n}\n.icon-circle-blank {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf10c;');\n}\n.icon-quote-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf10d;');\n}\n.icon-quote-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf10e;');\n}\n.icon-spinner {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf110;');\n}\n.icon-circle {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf111;');\n}\n.icon-reply {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf112;');\n}\n.icon-mail-reply {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf112;');\n}\n.icon-github-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf113;');\n}\n.icon-folder-close-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf114;');\n}\n.icon-folder-open-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf115;');\n}\n.icon-expand-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf116;');\n}\n.icon-collapse-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf117;');\n}\n.icon-smile {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf118;');\n}\n.icon-frown {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf119;');\n}\n.icon-meh {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf11a;');\n}\n.icon-gamepad {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf11b;');\n}\n.icon-keyboard {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf11c;');\n}\n.icon-flag-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf11d;');\n}\n.icon-flag-checkered {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf11e;');\n}\n.icon-terminal {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf120;');\n}\n.icon-code {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf121;');\n}\n.icon-reply-all {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf122;');\n}\n.icon-mail-reply-all {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf122;');\n}\n.icon-star-half-empty {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf123;');\n}\n.icon-star-half-full {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf123;');\n}\n.icon-location-arrow {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf124;');\n}\n.icon-crop {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf125;');\n}\n.icon-code-fork {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf126;');\n}\n.icon-unlink {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf127;');\n}\n.icon-question {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf128;');\n}\n.icon-info {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf129;');\n}\n.icon-exclamation {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf12a;');\n}\n.icon-superscript {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf12b;');\n}\n.icon-subscript {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf12c;');\n}\n.icon-eraser {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf12d;');\n}\n.icon-puzzle-piece {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf12e;');\n}\n.icon-microphone {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf130;');\n}\n.icon-microphone-off {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf131;');\n}\n.icon-shield {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf132;');\n}\n.icon-calendar-empty {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf133;');\n}\n.icon-fire-extinguisher {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf134;');\n}\n.icon-rocket {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf135;');\n}\n.icon-maxcdn {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf136;');\n}\n.icon-chevron-sign-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf137;');\n}\n.icon-chevron-sign-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf138;');\n}\n.icon-chevron-sign-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf139;');\n}\n.icon-chevron-sign-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf13a;');\n}\n.icon-html5 {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf13b;');\n}\n.icon-css3 {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf13c;');\n}\n.icon-anchor {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf13d;');\n}\n.icon-unlock-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf13e;');\n}\n.icon-bullseye {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf140;');\n}\n.icon-ellipsis-horizontal {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf141;');\n}\n.icon-ellipsis-vertical {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf142;');\n}\n.icon-rss-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf143;');\n}\n.icon-play-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf144;');\n}\n.icon-ticket {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf145;');\n}\n.icon-minus-sign-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf146;');\n}\n.icon-check-minus {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf147;');\n}\n.icon-level-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf148;');\n}\n.icon-level-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf149;');\n}\n.icon-check-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf14a;');\n}\n.icon-edit-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf14b;');\n}\n.icon-external-link-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf14c;');\n}\n.icon-share-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf14d;');\n}\n.icon-compass {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf14e;');\n}\n.icon-collapse {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf150;');\n}\n.icon-collapse-top {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf151;');\n}\n.icon-expand {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf152;');\n}\n.icon-eur {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf153;');\n}\n.icon-euro {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf153;');\n}\n.icon-gbp {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf154;');\n}\n.icon-usd {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf155;');\n}\n.icon-dollar {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf155;');\n}\n.icon-inr {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf156;');\n}\n.icon-rupee {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf156;');\n}\n.icon-jpy {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf157;');\n}\n.icon-yen {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf157;');\n}\n.icon-cny {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf158;');\n}\n.icon-renminbi {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf158;');\n}\n.icon-krw {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf159;');\n}\n.icon-won {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf159;');\n}\n.icon-btc {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf15a;');\n}\n.icon-bitcoin {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf15a;');\n}\n.icon-file {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf15b;');\n}\n.icon-file-text {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf15c;');\n}\n.icon-sort-by-alphabet {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf15d;');\n}\n.icon-sort-by-alphabet-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf15e;');\n}\n.icon-sort-by-attributes {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf160;');\n}\n.icon-sort-by-attributes-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf161;');\n}\n.icon-sort-by-order {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf162;');\n}\n.icon-sort-by-order-alt {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf163;');\n}\n.icon-thumbs-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf164;');\n}\n.icon-thumbs-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf165;');\n}\n.icon-youtube-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf166;');\n}\n.icon-youtube {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf167;');\n}\n.icon-xing {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf168;');\n}\n.icon-xing-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf169;');\n}\n.icon-youtube-play {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf16a;');\n}\n.icon-dropbox {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf16b;');\n}\n.icon-stackexchange {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf16c;');\n}\n.icon-instagram {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf16d;');\n}\n.icon-flickr {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf16e;');\n}\n.icon-adn {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf170;');\n}\n.icon-bitbucket {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf171;');\n}\n.icon-bitbucket-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf172;');\n}\n.icon-tumblr {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf173;');\n}\n.icon-tumblr-sign {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf174;');\n}\n.icon-long-arrow-down {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf175;');\n}\n.icon-long-arrow-up {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf176;');\n}\n.icon-long-arrow-left {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf177;');\n}\n.icon-long-arrow-right {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf178;');\n}\n.icon-apple {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf179;');\n}\n.icon-windows {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf17a;');\n}\n.icon-android {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf17b;');\n}\n.icon-linux {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf17c;');\n}\n.icon-dribbble {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf17d;');\n}\n.icon-skype {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf17e;');\n}\n.icon-foursquare {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf180;');\n}\n.icon-trello {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf181;');\n}\n.icon-female {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf182;');\n}\n.icon-male {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf183;');\n}\n.icon-gittip {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf184;');\n}\n.icon-sun {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf185;');\n}\n.icon-moon {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf186;');\n}\n.icon-archive {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf187;');\n}\n.icon-bug {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf188;');\n}\n.icon-vk {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf189;');\n}\n.icon-weibo {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf18a;');\n}\n.icon-renren {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf18b;');\n}\n"
  },
  {
    "path": "modules/agent/public/css/font-awesome/css/archive/font-awesome.css",
    "content": "/*!\n *  Font Awesome 3.2.1\n *  the iconic font designed for Bootstrap\n *  ------------------------------------------------------------------------------\n *  The full suite of pictographic icons, examples, and documentation can be\n *  found at http://fontawesome.io.  Stay up to date on Twitter at\n *  http://twitter.com/fontawesome.\n *\n *  License\n *  ------------------------------------------------------------------------------\n *  - The Font Awesome font is licensed under SIL OFL 1.1 -\n *    http://scripts.sil.org/OFL\n *  - Font Awesome CSS, LESS, and SASS files are licensed under MIT License -\n *    http://opensource.org/licenses/mit-license.html\n *  - Font Awesome documentation licensed under CC BY 3.0 -\n *    http://creativecommons.org/licenses/by/3.0/\n *  - Attribution is no longer required in Font Awesome 3.0, but much appreciated:\n *    \"Font Awesome by Dave Gandy - http://fontawesome.io\"\n *\n *  Author - Dave Gandy\n *  ------------------------------------------------------------------------------\n *  Email: dave@fontawesome.io\n *  Twitter: http://twitter.com/davegandy\n *  Work: Lead Product Designer @ Kyruus - http://kyruus.com\n */\n/* FONT PATH\n * -------------------------- */\n@font-face {\n  font-family: 'FontAwesome';\n  src: url('../font/fontawesome-webfont.eot?v=3.2.1');\n  src: url('../font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('../font/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('../font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('../font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n/* FONT AWESOME CORE\n * -------------------------- */\n[class^=\"icon-\"],\n[class*=\" icon-\"] {\n  font-family: FontAwesome;\n  font-weight: normal;\n  font-style: normal;\n  text-decoration: inherit;\n  -webkit-font-smoothing: antialiased;\n  *margin-right: .3em;\n}\n[class^=\"icon-\"]:before,\n[class*=\" icon-\"]:before {\n  text-decoration: inherit;\n  display: inline-block;\n  speak: none;\n}\n/* makes the font 33% larger relative to the icon container */\n.icon-large:before {\n  vertical-align: -10%;\n  font-size: 1.3333333333333333em;\n}\n/* makes sure icons active on rollover in links */\na [class^=\"icon-\"],\na [class*=\" icon-\"] {\n  display: inline;\n}\n/* increased font size for icon-large */\n[class^=\"icon-\"].icon-fixed-width,\n[class*=\" icon-\"].icon-fixed-width {\n  display: inline-block;\n  width: 1.1428571428571428em;\n  text-align: right;\n  padding-right: 0.2857142857142857em;\n}\n[class^=\"icon-\"].icon-fixed-width.icon-large,\n[class*=\" icon-\"].icon-fixed-width.icon-large {\n  width: 1.4285714285714286em;\n}\n.icons-ul {\n  margin-left: 2.142857142857143em;\n  list-style-type: none;\n}\n.icons-ul > li {\n  position: relative;\n}\n.icons-ul .icon-li {\n  position: absolute;\n  left: -2.142857142857143em;\n  width: 2.142857142857143em;\n  text-align: center;\n  line-height: inherit;\n}\n[class^=\"icon-\"].hide,\n[class*=\" icon-\"].hide {\n  display: none;\n}\n.icon-muted {\n  color: #eeeeee;\n}\n.icon-light {\n  color: #ffffff;\n}\n.icon-dark {\n  color: #333333;\n}\n.icon-border {\n  border: solid 1px #eeeeee;\n  padding: .2em .25em .15em;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  border-radius: 3px;\n}\n.icon-2x {\n  font-size: 2em;\n}\n.icon-2x.icon-border {\n  border-width: 2px;\n  -webkit-border-radius: 4px;\n  -moz-border-radius: 4px;\n  border-radius: 4px;\n}\n.icon-3x {\n  font-size: 3em;\n}\n.icon-3x.icon-border {\n  border-width: 3px;\n  -webkit-border-radius: 5px;\n  -moz-border-radius: 5px;\n  border-radius: 5px;\n}\n.icon-4x {\n  font-size: 4em;\n}\n.icon-4x.icon-border {\n  border-width: 4px;\n  -webkit-border-radius: 6px;\n  -moz-border-radius: 6px;\n  border-radius: 6px;\n}\n.icon-5x {\n  font-size: 5em;\n}\n.icon-5x.icon-border {\n  border-width: 5px;\n  -webkit-border-radius: 7px;\n  -moz-border-radius: 7px;\n  border-radius: 7px;\n}\n.pull-right {\n  float: right;\n}\n.pull-left {\n  float: left;\n}\n[class^=\"icon-\"].pull-left,\n[class*=\" icon-\"].pull-left {\n  margin-right: .3em;\n}\n[class^=\"icon-\"].pull-right,\n[class*=\" icon-\"].pull-right {\n  margin-left: .3em;\n}\n/* BOOTSTRAP SPECIFIC CLASSES\n * -------------------------- */\n/* Bootstrap 2.0 sprites.less reset */\n[class^=\"icon-\"],\n[class*=\" icon-\"] {\n  display: inline;\n  width: auto;\n  height: auto;\n  line-height: normal;\n  vertical-align: baseline;\n  background-image: none;\n  background-position: 0% 0%;\n  background-repeat: repeat;\n  margin-top: 0;\n}\n/* more sprites.less reset */\n.icon-white,\n.nav-pills > .active > a > [class^=\"icon-\"],\n.nav-pills > .active > a > [class*=\" icon-\"],\n.nav-list > .active > a > [class^=\"icon-\"],\n.nav-list > .active > a > [class*=\" icon-\"],\n.navbar-inverse .nav > .active > a > [class^=\"icon-\"],\n.navbar-inverse .nav > .active > a > [class*=\" icon-\"],\n.dropdown-menu > li > a:hover > [class^=\"icon-\"],\n.dropdown-menu > li > a:hover > [class*=\" icon-\"],\n.dropdown-menu > .active > a > [class^=\"icon-\"],\n.dropdown-menu > .active > a > [class*=\" icon-\"],\n.dropdown-submenu:hover > a > [class^=\"icon-\"],\n.dropdown-submenu:hover > a > [class*=\" icon-\"] {\n  background-image: none;\n}\n/* keeps Bootstrap styles with and without icons the same */\n.btn [class^=\"icon-\"].icon-large,\n.nav [class^=\"icon-\"].icon-large,\n.btn [class*=\" icon-\"].icon-large,\n.nav [class*=\" icon-\"].icon-large {\n  line-height: .9em;\n}\n.btn [class^=\"icon-\"].icon-spin,\n.nav [class^=\"icon-\"].icon-spin,\n.btn [class*=\" icon-\"].icon-spin,\n.nav [class*=\" icon-\"].icon-spin {\n  display: inline-block;\n}\n.nav-tabs [class^=\"icon-\"],\n.nav-pills [class^=\"icon-\"],\n.nav-tabs [class*=\" icon-\"],\n.nav-pills [class*=\" icon-\"],\n.nav-tabs [class^=\"icon-\"].icon-large,\n.nav-pills [class^=\"icon-\"].icon-large,\n.nav-tabs [class*=\" icon-\"].icon-large,\n.nav-pills [class*=\" icon-\"].icon-large {\n  line-height: .9em;\n}\n.btn [class^=\"icon-\"].pull-left.icon-2x,\n.btn [class*=\" icon-\"].pull-left.icon-2x,\n.btn [class^=\"icon-\"].pull-right.icon-2x,\n.btn [class*=\" icon-\"].pull-right.icon-2x {\n  margin-top: .18em;\n}\n.btn [class^=\"icon-\"].icon-spin.icon-large,\n.btn [class*=\" icon-\"].icon-spin.icon-large {\n  line-height: .8em;\n}\n.btn.btn-small [class^=\"icon-\"].pull-left.icon-2x,\n.btn.btn-small [class*=\" icon-\"].pull-left.icon-2x,\n.btn.btn-small [class^=\"icon-\"].pull-right.icon-2x,\n.btn.btn-small [class*=\" icon-\"].pull-right.icon-2x {\n  margin-top: .25em;\n}\n.btn.btn-large [class^=\"icon-\"],\n.btn.btn-large [class*=\" icon-\"] {\n  margin-top: 0;\n}\n.btn.btn-large [class^=\"icon-\"].pull-left.icon-2x,\n.btn.btn-large [class*=\" icon-\"].pull-left.icon-2x,\n.btn.btn-large [class^=\"icon-\"].pull-right.icon-2x,\n.btn.btn-large [class*=\" icon-\"].pull-right.icon-2x {\n  margin-top: .05em;\n}\n.btn.btn-large [class^=\"icon-\"].pull-left.icon-2x,\n.btn.btn-large [class*=\" icon-\"].pull-left.icon-2x {\n  margin-right: .2em;\n}\n.btn.btn-large [class^=\"icon-\"].pull-right.icon-2x,\n.btn.btn-large [class*=\" icon-\"].pull-right.icon-2x {\n  margin-left: .2em;\n}\n/* Fixes alignment in nav lists */\n.nav-list [class^=\"icon-\"],\n.nav-list [class*=\" icon-\"] {\n  line-height: inherit;\n}\n/* EXTRAS\n * -------------------------- */\n/* Stacked and layered icon */\n.icon-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: -35%;\n}\n.icon-stack [class^=\"icon-\"],\n.icon-stack [class*=\" icon-\"] {\n  display: block;\n  text-align: center;\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  font-size: 1em;\n  line-height: inherit;\n  *line-height: 2em;\n}\n.icon-stack .icon-stack-base {\n  font-size: 2em;\n  *line-height: 1em;\n}\n/* Animated rotating icon */\n.icon-spin {\n  display: inline-block;\n  -moz-animation: spin 2s infinite linear;\n  -o-animation: spin 2s infinite linear;\n  -webkit-animation: spin 2s infinite linear;\n  animation: spin 2s infinite linear;\n}\n/* Prevent stack and spinners from being taken inline when inside a link */\na .icon-stack,\na .icon-spin {\n  display: inline-block;\n  text-decoration: none;\n}\n@-moz-keyframes spin {\n  0% {\n    -moz-transform: rotate(0deg);\n  }\n  100% {\n    -moz-transform: rotate(359deg);\n  }\n}\n@-webkit-keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n  }\n}\n@-o-keyframes spin {\n  0% {\n    -o-transform: rotate(0deg);\n  }\n  100% {\n    -o-transform: rotate(359deg);\n  }\n}\n@-ms-keyframes spin {\n  0% {\n    -ms-transform: rotate(0deg);\n  }\n  100% {\n    -ms-transform: rotate(359deg);\n  }\n}\n@keyframes spin {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(359deg);\n  }\n}\n/* Icon rotations and mirroring */\n.icon-rotate-90:before {\n  -webkit-transform: rotate(90deg);\n  -moz-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  -o-transform: rotate(90deg);\n  transform: rotate(90deg);\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);\n}\n.icon-rotate-180:before {\n  -webkit-transform: rotate(180deg);\n  -moz-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  -o-transform: rotate(180deg);\n  transform: rotate(180deg);\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n}\n.icon-rotate-270:before {\n  -webkit-transform: rotate(270deg);\n  -moz-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  -o-transform: rotate(270deg);\n  transform: rotate(270deg);\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);\n}\n.icon-flip-horizontal:before {\n  -webkit-transform: scale(-1, 1);\n  -moz-transform: scale(-1, 1);\n  -ms-transform: scale(-1, 1);\n  -o-transform: scale(-1, 1);\n  transform: scale(-1, 1);\n}\n.icon-flip-vertical:before {\n  -webkit-transform: scale(1, -1);\n  -moz-transform: scale(1, -1);\n  -ms-transform: scale(1, -1);\n  -o-transform: scale(1, -1);\n  transform: scale(1, -1);\n}\n/* ensure rotation occurs inside anchor tags */\na .icon-rotate-90:before,\na .icon-rotate-180:before,\na .icon-rotate-270:before,\na .icon-flip-horizontal:before,\na .icon-flip-vertical:before {\n  display: inline-block;\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.icon-glass:before {\n  content: \"\\f000\";\n}\n.icon-music:before {\n  content: \"\\f001\";\n}\n.icon-search:before {\n  content: \"\\f002\";\n}\n.icon-envelope-alt:before {\n  content: \"\\f003\";\n}\n.icon-heart:before {\n  content: \"\\f004\";\n}\n.icon-star:before {\n  content: \"\\f005\";\n}\n.icon-star-empty:before {\n  content: \"\\f006\";\n}\n.icon-user:before {\n  content: \"\\f007\";\n}\n.icon-film:before {\n  content: \"\\f008\";\n}\n.icon-th-large:before {\n  content: \"\\f009\";\n}\n.icon-th:before {\n  content: \"\\f00a\";\n}\n.icon-th-list:before {\n  content: \"\\f00b\";\n}\n.icon-ok:before {\n  content: \"\\f00c\";\n}\n.icon-remove:before {\n  content: \"\\f00d\";\n}\n.icon-zoom-in:before {\n  content: \"\\f00e\";\n}\n.icon-zoom-out:before {\n  content: \"\\f010\";\n}\n.icon-power-off:before,\n.icon-off:before {\n  content: \"\\f011\";\n}\n.icon-signal:before {\n  content: \"\\f012\";\n}\n.icon-gear:before,\n.icon-cog:before {\n  content: \"\\f013\";\n}\n.icon-trash:before {\n  content: \"\\f014\";\n}\n.icon-home:before {\n  content: \"\\f015\";\n}\n.icon-file-alt:before {\n  content: \"\\f016\";\n}\n.icon-time:before {\n  content: \"\\f017\";\n}\n.icon-road:before {\n  content: \"\\f018\";\n}\n.icon-download-alt:before {\n  content: \"\\f019\";\n}\n.icon-download:before {\n  content: \"\\f01a\";\n}\n.icon-upload:before {\n  content: \"\\f01b\";\n}\n.icon-inbox:before {\n  content: \"\\f01c\";\n}\n.icon-play-circle:before {\n  content: \"\\f01d\";\n}\n.icon-rotate-right:before,\n.icon-repeat:before {\n  content: \"\\f01e\";\n}\n.icon-refresh:before {\n  content: \"\\f021\";\n}\n.icon-list-alt:before {\n  content: \"\\f022\";\n}\n.icon-lock:before {\n  content: \"\\f023\";\n}\n.icon-flag:before {\n  content: \"\\f024\";\n}\n.icon-headphones:before {\n  content: \"\\f025\";\n}\n.icon-volume-off:before {\n  content: \"\\f026\";\n}\n.icon-volume-down:before {\n  content: \"\\f027\";\n}\n.icon-volume-up:before {\n  content: \"\\f028\";\n}\n.icon-qrcode:before {\n  content: \"\\f029\";\n}\n.icon-barcode:before {\n  content: \"\\f02a\";\n}\n.icon-tag:before {\n  content: \"\\f02b\";\n}\n.icon-tags:before {\n  content: \"\\f02c\";\n}\n.icon-book:before {\n  content: \"\\f02d\";\n}\n.icon-bookmark:before {\n  content: \"\\f02e\";\n}\n.icon-print:before {\n  content: \"\\f02f\";\n}\n.icon-camera:before {\n  content: \"\\f030\";\n}\n.icon-font:before {\n  content: \"\\f031\";\n}\n.icon-bold:before {\n  content: \"\\f032\";\n}\n.icon-italic:before {\n  content: \"\\f033\";\n}\n.icon-text-height:before {\n  content: \"\\f034\";\n}\n.icon-text-width:before {\n  content: \"\\f035\";\n}\n.icon-align-left:before {\n  content: \"\\f036\";\n}\n.icon-align-center:before {\n  content: \"\\f037\";\n}\n.icon-align-right:before {\n  content: \"\\f038\";\n}\n.icon-align-justify:before {\n  content: \"\\f039\";\n}\n.icon-list:before {\n  content: \"\\f03a\";\n}\n.icon-indent-left:before {\n  content: \"\\f03b\";\n}\n.icon-indent-right:before {\n  content: \"\\f03c\";\n}\n.icon-facetime-video:before {\n  content: \"\\f03d\";\n}\n.icon-picture:before {\n  content: \"\\f03e\";\n}\n.icon-pencil:before {\n  content: \"\\f040\";\n}\n.icon-map-marker:before {\n  content: \"\\f041\";\n}\n.icon-adjust:before {\n  content: \"\\f042\";\n}\n.icon-tint:before {\n  content: \"\\f043\";\n}\n.icon-edit:before {\n  content: \"\\f044\";\n}\n.icon-share:before {\n  content: \"\\f045\";\n}\n.icon-check:before {\n  content: \"\\f046\";\n}\n.icon-move:before {\n  content: \"\\f047\";\n}\n.icon-step-backward:before {\n  content: \"\\f048\";\n}\n.icon-fast-backward:before {\n  content: \"\\f049\";\n}\n.icon-backward:before {\n  content: \"\\f04a\";\n}\n.icon-play:before {\n  content: \"\\f04b\";\n}\n.icon-pause:before {\n  content: \"\\f04c\";\n}\n.icon-stop:before {\n  content: \"\\f04d\";\n}\n.icon-forward:before {\n  content: \"\\f04e\";\n}\n.icon-fast-forward:before {\n  content: \"\\f050\";\n}\n.icon-step-forward:before {\n  content: \"\\f051\";\n}\n.icon-eject:before {\n  content: \"\\f052\";\n}\n.icon-chevron-left:before {\n  content: \"\\f053\";\n}\n.icon-chevron-right:before {\n  content: \"\\f054\";\n}\n.icon-plus-sign:before {\n  content: \"\\f055\";\n}\n.icon-minus-sign:before {\n  content: \"\\f056\";\n}\n.icon-remove-sign:before {\n  content: \"\\f057\";\n}\n.icon-ok-sign:before {\n  content: \"\\f058\";\n}\n.icon-question-sign:before {\n  content: \"\\f059\";\n}\n.icon-info-sign:before {\n  content: \"\\f05a\";\n}\n.icon-screenshot:before {\n  content: \"\\f05b\";\n}\n.icon-remove-circle:before {\n  content: \"\\f05c\";\n}\n.icon-ok-circle:before {\n  content: \"\\f05d\";\n}\n.icon-ban-circle:before {\n  content: \"\\f05e\";\n}\n.icon-arrow-left:before {\n  content: \"\\f060\";\n}\n.icon-arrow-right:before {\n  content: \"\\f061\";\n}\n.icon-arrow-up:before {\n  content: \"\\f062\";\n}\n.icon-arrow-down:before {\n  content: \"\\f063\";\n}\n.icon-mail-forward:before,\n.icon-share-alt:before {\n  content: \"\\f064\";\n}\n.icon-resize-full:before {\n  content: \"\\f065\";\n}\n.icon-resize-small:before {\n  content: \"\\f066\";\n}\n.icon-plus:before {\n  content: \"\\f067\";\n}\n.icon-minus:before {\n  content: \"\\f068\";\n}\n.icon-asterisk:before {\n  content: \"\\f069\";\n}\n.icon-exclamation-sign:before {\n  content: \"\\f06a\";\n}\n.icon-gift:before {\n  content: \"\\f06b\";\n}\n.icon-leaf:before {\n  content: \"\\f06c\";\n}\n.icon-fire:before {\n  content: \"\\f06d\";\n}\n.icon-eye-open:before {\n  content: \"\\f06e\";\n}\n.icon-eye-close:before {\n  content: \"\\f070\";\n}\n.icon-warning-sign:before {\n  content: \"\\f071\";\n}\n.icon-plane:before {\n  content: \"\\f072\";\n}\n.icon-calendar:before {\n  content: \"\\f073\";\n}\n.icon-random:before {\n  content: \"\\f074\";\n}\n.icon-comment:before {\n  content: \"\\f075\";\n}\n.icon-magnet:before {\n  content: \"\\f076\";\n}\n.icon-chevron-up:before {\n  content: \"\\f077\";\n}\n.icon-chevron-down:before {\n  content: \"\\f078\";\n}\n.icon-retweet:before {\n  content: \"\\f079\";\n}\n.icon-shopping-cart:before {\n  content: \"\\f07a\";\n}\n.icon-folder-close:before {\n  content: \"\\f07b\";\n}\n.icon-folder-open:before {\n  content: \"\\f07c\";\n}\n.icon-resize-vertical:before {\n  content: \"\\f07d\";\n}\n.icon-resize-horizontal:before {\n  content: \"\\f07e\";\n}\n.icon-bar-chart:before {\n  content: \"\\f080\";\n}\n.icon-twitter-sign:before {\n  content: \"\\f081\";\n}\n.icon-facebook-sign:before {\n  content: \"\\f082\";\n}\n.icon-camera-retro:before {\n  content: \"\\f083\";\n}\n.icon-key:before {\n  content: \"\\f084\";\n}\n.icon-gears:before,\n.icon-cogs:before {\n  content: \"\\f085\";\n}\n.icon-comments:before {\n  content: \"\\f086\";\n}\n.icon-thumbs-up-alt:before {\n  content: \"\\f087\";\n}\n.icon-thumbs-down-alt:before {\n  content: \"\\f088\";\n}\n.icon-star-half:before {\n  content: \"\\f089\";\n}\n.icon-heart-empty:before {\n  content: \"\\f08a\";\n}\n.icon-signout:before {\n  content: \"\\f08b\";\n}\n.icon-linkedin-sign:before {\n  content: \"\\f08c\";\n}\n.icon-pushpin:before {\n  content: \"\\f08d\";\n}\n.icon-external-link:before {\n  content: \"\\f08e\";\n}\n.icon-signin:before {\n  content: \"\\f090\";\n}\n.icon-trophy:before {\n  content: \"\\f091\";\n}\n.icon-github-sign:before {\n  content: \"\\f092\";\n}\n.icon-upload-alt:before {\n  content: \"\\f093\";\n}\n.icon-lemon:before {\n  content: \"\\f094\";\n}\n.icon-phone:before {\n  content: \"\\f095\";\n}\n.icon-unchecked:before,\n.icon-check-empty:before {\n  content: \"\\f096\";\n}\n.icon-bookmark-empty:before {\n  content: \"\\f097\";\n}\n.icon-phone-sign:before {\n  content: \"\\f098\";\n}\n.icon-twitter:before {\n  content: \"\\f099\";\n}\n.icon-facebook:before {\n  content: \"\\f09a\";\n}\n.icon-github:before {\n  content: \"\\f09b\";\n}\n.icon-unlock:before {\n  content: \"\\f09c\";\n}\n.icon-credit-card:before {\n  content: \"\\f09d\";\n}\n.icon-rss:before {\n  content: \"\\f09e\";\n}\n.icon-hdd:before {\n  content: \"\\f0a0\";\n}\n.icon-bullhorn:before {\n  content: \"\\f0a1\";\n}\n.icon-bell:before {\n  content: \"\\f0a2\";\n}\n.icon-certificate:before {\n  content: \"\\f0a3\";\n}\n.icon-hand-right:before {\n  content: \"\\f0a4\";\n}\n.icon-hand-left:before {\n  content: \"\\f0a5\";\n}\n.icon-hand-up:before {\n  content: \"\\f0a6\";\n}\n.icon-hand-down:before {\n  content: \"\\f0a7\";\n}\n.icon-circle-arrow-left:before {\n  content: \"\\f0a8\";\n}\n.icon-circle-arrow-right:before {\n  content: \"\\f0a9\";\n}\n.icon-circle-arrow-up:before {\n  content: \"\\f0aa\";\n}\n.icon-circle-arrow-down:before {\n  content: \"\\f0ab\";\n}\n.icon-globe:before {\n  content: \"\\f0ac\";\n}\n.icon-wrench:before {\n  content: \"\\f0ad\";\n}\n.icon-tasks:before {\n  content: \"\\f0ae\";\n}\n.icon-filter:before {\n  content: \"\\f0b0\";\n}\n.icon-briefcase:before {\n  content: \"\\f0b1\";\n}\n.icon-fullscreen:before {\n  content: \"\\f0b2\";\n}\n.icon-group:before {\n  content: \"\\f0c0\";\n}\n.icon-link:before {\n  content: \"\\f0c1\";\n}\n.icon-cloud:before {\n  content: \"\\f0c2\";\n}\n.icon-beaker:before {\n  content: \"\\f0c3\";\n}\n.icon-cut:before {\n  content: \"\\f0c4\";\n}\n.icon-copy:before {\n  content: \"\\f0c5\";\n}\n.icon-paperclip:before,\n.icon-paper-clip:before {\n  content: \"\\f0c6\";\n}\n.icon-save:before {\n  content: \"\\f0c7\";\n}\n.icon-sign-blank:before {\n  content: \"\\f0c8\";\n}\n.icon-reorder:before {\n  content: \"\\f0c9\";\n}\n.icon-list-ul:before {\n  content: \"\\f0ca\";\n}\n.icon-list-ol:before {\n  content: \"\\f0cb\";\n}\n.icon-strikethrough:before {\n  content: \"\\f0cc\";\n}\n.icon-underline:before {\n  content: \"\\f0cd\";\n}\n.icon-table:before {\n  content: \"\\f0ce\";\n}\n.icon-magic:before {\n  content: \"\\f0d0\";\n}\n.icon-truck:before {\n  content: \"\\f0d1\";\n}\n.icon-pinterest:before {\n  content: \"\\f0d2\";\n}\n.icon-pinterest-sign:before {\n  content: \"\\f0d3\";\n}\n.icon-google-plus-sign:before {\n  content: \"\\f0d4\";\n}\n.icon-google-plus:before {\n  content: \"\\f0d5\";\n}\n.icon-money:before {\n  content: \"\\f0d6\";\n}\n.icon-caret-down:before {\n  content: \"\\f0d7\";\n}\n.icon-caret-up:before {\n  content: \"\\f0d8\";\n}\n.icon-caret-left:before {\n  content: \"\\f0d9\";\n}\n.icon-caret-right:before {\n  content: \"\\f0da\";\n}\n.icon-columns:before {\n  content: \"\\f0db\";\n}\n.icon-sort:before {\n  content: \"\\f0dc\";\n}\n.icon-sort-down:before {\n  content: \"\\f0dd\";\n}\n.icon-sort-up:before {\n  content: \"\\f0de\";\n}\n.icon-envelope:before {\n  content: \"\\f0e0\";\n}\n.icon-linkedin:before {\n  content: \"\\f0e1\";\n}\n.icon-rotate-left:before,\n.icon-undo:before {\n  content: \"\\f0e2\";\n}\n.icon-legal:before {\n  content: \"\\f0e3\";\n}\n.icon-dashboard:before {\n  content: \"\\f0e4\";\n}\n.icon-comment-alt:before {\n  content: \"\\f0e5\";\n}\n.icon-comments-alt:before {\n  content: \"\\f0e6\";\n}\n.icon-bolt:before {\n  content: \"\\f0e7\";\n}\n.icon-sitemap:before {\n  content: \"\\f0e8\";\n}\n.icon-umbrella:before {\n  content: \"\\f0e9\";\n}\n.icon-paste:before {\n  content: \"\\f0ea\";\n}\n.icon-lightbulb:before {\n  content: \"\\f0eb\";\n}\n.icon-exchange:before {\n  content: \"\\f0ec\";\n}\n.icon-cloud-download:before {\n  content: \"\\f0ed\";\n}\n.icon-cloud-upload:before {\n  content: \"\\f0ee\";\n}\n.icon-user-md:before {\n  content: \"\\f0f0\";\n}\n.icon-stethoscope:before {\n  content: \"\\f0f1\";\n}\n.icon-suitcase:before {\n  content: \"\\f0f2\";\n}\n.icon-bell-alt:before {\n  content: \"\\f0f3\";\n}\n.icon-coffee:before {\n  content: \"\\f0f4\";\n}\n.icon-food:before {\n  content: \"\\f0f5\";\n}\n.icon-file-text-alt:before {\n  content: \"\\f0f6\";\n}\n.icon-building:before {\n  content: \"\\f0f7\";\n}\n.icon-hospital:before {\n  content: \"\\f0f8\";\n}\n.icon-ambulance:before {\n  content: \"\\f0f9\";\n}\n.icon-medkit:before {\n  content: \"\\f0fa\";\n}\n.icon-fighter-jet:before {\n  content: \"\\f0fb\";\n}\n.icon-beer:before {\n  content: \"\\f0fc\";\n}\n.icon-h-sign:before {\n  content: \"\\f0fd\";\n}\n.icon-plus-sign-alt:before {\n  content: \"\\f0fe\";\n}\n.icon-double-angle-left:before {\n  content: \"\\f100\";\n}\n.icon-double-angle-right:before {\n  content: \"\\f101\";\n}\n.icon-double-angle-up:before {\n  content: \"\\f102\";\n}\n.icon-double-angle-down:before {\n  content: \"\\f103\";\n}\n.icon-angle-left:before {\n  content: \"\\f104\";\n}\n.icon-angle-right:before {\n  content: \"\\f105\";\n}\n.icon-angle-up:before {\n  content: \"\\f106\";\n}\n.icon-angle-down:before {\n  content: \"\\f107\";\n}\n.icon-desktop:before {\n  content: \"\\f108\";\n}\n.icon-laptop:before {\n  content: \"\\f109\";\n}\n.icon-tablet:before {\n  content: \"\\f10a\";\n}\n.icon-mobile-phone:before {\n  content: \"\\f10b\";\n}\n.icon-circle-blank:before {\n  content: \"\\f10c\";\n}\n.icon-quote-left:before {\n  content: \"\\f10d\";\n}\n.icon-quote-right:before {\n  content: \"\\f10e\";\n}\n.icon-spinner:before {\n  content: \"\\f110\";\n}\n.icon-circle:before {\n  content: \"\\f111\";\n}\n.icon-mail-reply:before,\n.icon-reply:before {\n  content: \"\\f112\";\n}\n.icon-github-alt:before {\n  content: \"\\f113\";\n}\n.icon-folder-close-alt:before {\n  content: \"\\f114\";\n}\n.icon-folder-open-alt:before {\n  content: \"\\f115\";\n}\n.icon-expand-alt:before {\n  content: \"\\f116\";\n}\n.icon-collapse-alt:before {\n  content: \"\\f117\";\n}\n.icon-smile:before {\n  content: \"\\f118\";\n}\n.icon-frown:before {\n  content: \"\\f119\";\n}\n.icon-meh:before {\n  content: \"\\f11a\";\n}\n.icon-gamepad:before {\n  content: \"\\f11b\";\n}\n.icon-keyboard:before {\n  content: \"\\f11c\";\n}\n.icon-flag-alt:before {\n  content: \"\\f11d\";\n}\n.icon-flag-checkered:before {\n  content: \"\\f11e\";\n}\n.icon-terminal:before {\n  content: \"\\f120\";\n}\n.icon-code:before {\n  content: \"\\f121\";\n}\n.icon-reply-all:before {\n  content: \"\\f122\";\n}\n.icon-mail-reply-all:before {\n  content: \"\\f122\";\n}\n.icon-star-half-full:before,\n.icon-star-half-empty:before {\n  content: \"\\f123\";\n}\n.icon-location-arrow:before {\n  content: \"\\f124\";\n}\n.icon-crop:before {\n  content: \"\\f125\";\n}\n.icon-code-fork:before {\n  content: \"\\f126\";\n}\n.icon-unlink:before {\n  content: \"\\f127\";\n}\n.icon-question:before {\n  content: \"\\f128\";\n}\n.icon-info:before {\n  content: \"\\f129\";\n}\n.icon-exclamation:before {\n  content: \"\\f12a\";\n}\n.icon-superscript:before {\n  content: \"\\f12b\";\n}\n.icon-subscript:before {\n  content: \"\\f12c\";\n}\n.icon-eraser:before {\n  content: \"\\f12d\";\n}\n.icon-puzzle-piece:before {\n  content: \"\\f12e\";\n}\n.icon-microphone:before {\n  content: \"\\f130\";\n}\n.icon-microphone-off:before {\n  content: \"\\f131\";\n}\n.icon-shield:before {\n  content: \"\\f132\";\n}\n.icon-calendar-empty:before {\n  content: \"\\f133\";\n}\n.icon-fire-extinguisher:before {\n  content: \"\\f134\";\n}\n.icon-rocket:before {\n  content: \"\\f135\";\n}\n.icon-maxcdn:before {\n  content: \"\\f136\";\n}\n.icon-chevron-sign-left:before {\n  content: \"\\f137\";\n}\n.icon-chevron-sign-right:before {\n  content: \"\\f138\";\n}\n.icon-chevron-sign-up:before {\n  content: \"\\f139\";\n}\n.icon-chevron-sign-down:before {\n  content: \"\\f13a\";\n}\n.icon-html5:before {\n  content: \"\\f13b\";\n}\n.icon-css3:before {\n  content: \"\\f13c\";\n}\n.icon-anchor:before {\n  content: \"\\f13d\";\n}\n.icon-unlock-alt:before {\n  content: \"\\f13e\";\n}\n.icon-bullseye:before {\n  content: \"\\f140\";\n}\n.icon-ellipsis-horizontal:before {\n  content: \"\\f141\";\n}\n.icon-ellipsis-vertical:before {\n  content: \"\\f142\";\n}\n.icon-rss-sign:before {\n  content: \"\\f143\";\n}\n.icon-play-sign:before {\n  content: \"\\f144\";\n}\n.icon-ticket:before {\n  content: \"\\f145\";\n}\n.icon-minus-sign-alt:before {\n  content: \"\\f146\";\n}\n.icon-check-minus:before {\n  content: \"\\f147\";\n}\n.icon-level-up:before {\n  content: \"\\f148\";\n}\n.icon-level-down:before {\n  content: \"\\f149\";\n}\n.icon-check-sign:before {\n  content: \"\\f14a\";\n}\n.icon-edit-sign:before {\n  content: \"\\f14b\";\n}\n.icon-external-link-sign:before {\n  content: \"\\f14c\";\n}\n.icon-share-sign:before {\n  content: \"\\f14d\";\n}\n.icon-compass:before {\n  content: \"\\f14e\";\n}\n.icon-collapse:before {\n  content: \"\\f150\";\n}\n.icon-collapse-top:before {\n  content: \"\\f151\";\n}\n.icon-expand:before {\n  content: \"\\f152\";\n}\n.icon-euro:before,\n.icon-eur:before {\n  content: \"\\f153\";\n}\n.icon-gbp:before {\n  content: \"\\f154\";\n}\n.icon-dollar:before,\n.icon-usd:before {\n  content: \"\\f155\";\n}\n.icon-rupee:before,\n.icon-inr:before {\n  content: \"\\f156\";\n}\n.icon-yen:before,\n.icon-jpy:before {\n  content: \"\\f157\";\n}\n.icon-renminbi:before,\n.icon-cny:before {\n  content: \"\\f158\";\n}\n.icon-won:before,\n.icon-krw:before {\n  content: \"\\f159\";\n}\n.icon-bitcoin:before,\n.icon-btc:before {\n  content: \"\\f15a\";\n}\n.icon-file:before {\n  content: \"\\f15b\";\n}\n.icon-file-text:before {\n  content: \"\\f15c\";\n}\n.icon-sort-by-alphabet:before {\n  content: \"\\f15d\";\n}\n.icon-sort-by-alphabet-alt:before {\n  content: \"\\f15e\";\n}\n.icon-sort-by-attributes:before {\n  content: \"\\f160\";\n}\n.icon-sort-by-attributes-alt:before {\n  content: \"\\f161\";\n}\n.icon-sort-by-order:before {\n  content: \"\\f162\";\n}\n.icon-sort-by-order-alt:before {\n  content: \"\\f163\";\n}\n.icon-thumbs-up:before {\n  content: \"\\f164\";\n}\n.icon-thumbs-down:before {\n  content: \"\\f165\";\n}\n.icon-youtube-sign:before {\n  content: \"\\f166\";\n}\n.icon-youtube:before {\n  content: \"\\f167\";\n}\n.icon-xing:before {\n  content: \"\\f168\";\n}\n.icon-xing-sign:before {\n  content: \"\\f169\";\n}\n.icon-youtube-play:before {\n  content: \"\\f16a\";\n}\n.icon-dropbox:before {\n  content: \"\\f16b\";\n}\n.icon-stackexchange:before {\n  content: \"\\f16c\";\n}\n.icon-instagram:before {\n  content: \"\\f16d\";\n}\n.icon-flickr:before {\n  content: \"\\f16e\";\n}\n.icon-adn:before {\n  content: \"\\f170\";\n}\n.icon-bitbucket:before {\n  content: \"\\f171\";\n}\n.icon-bitbucket-sign:before {\n  content: \"\\f172\";\n}\n.icon-tumblr:before {\n  content: \"\\f173\";\n}\n.icon-tumblr-sign:before {\n  content: \"\\f174\";\n}\n.icon-long-arrow-down:before {\n  content: \"\\f175\";\n}\n.icon-long-arrow-up:before {\n  content: \"\\f176\";\n}\n.icon-long-arrow-left:before {\n  content: \"\\f177\";\n}\n.icon-long-arrow-right:before {\n  content: \"\\f178\";\n}\n.icon-apple:before {\n  content: \"\\f179\";\n}\n.icon-windows:before {\n  content: \"\\f17a\";\n}\n.icon-android:before {\n  content: \"\\f17b\";\n}\n.icon-linux:before {\n  content: \"\\f17c\";\n}\n.icon-dribbble:before {\n  content: \"\\f17d\";\n}\n.icon-skype:before {\n  content: \"\\f17e\";\n}\n.icon-foursquare:before {\n  content: \"\\f180\";\n}\n.icon-trello:before {\n  content: \"\\f181\";\n}\n.icon-female:before {\n  content: \"\\f182\";\n}\n.icon-male:before {\n  content: \"\\f183\";\n}\n.icon-gittip:before {\n  content: \"\\f184\";\n}\n.icon-sun:before {\n  content: \"\\f185\";\n}\n.icon-moon:before {\n  content: \"\\f186\";\n}\n.icon-archive:before {\n  content: \"\\f187\";\n}\n.icon-bug:before {\n  content: \"\\f188\";\n}\n.icon-vk:before {\n  content: \"\\f189\";\n}\n.icon-weibo:before {\n  content: \"\\f18a\";\n}\n.icon-renren:before {\n  content: \"\\f18b\";\n}\n"
  },
  {
    "path": "modules/agent/public/css/g.css",
    "content": "*{ font:11pt Verdana,Arial,Microsoft YaHei,sans-serif; color:#111; word-wrap:break-word;}\nth {font-weight: bold;}\nh3.tit {font-weight: bold; border-left: 3px solid #FF8000; padding-left: 5px;}\n.mt0{ margin-top:0px!important;}\n.mt5{ margin-top:5px!important;}\n.mt10{ margin-top:10px!important;}\n.m10{ margin:10px!important;}\n.mt15{ margin-top:15px!important;}\n.mt20{ margin-top:20px!important;}\n.mb0{ margin-bottom:0px!important;}\n.mb5{ margin-bottom:5px!important;}\n.mb10{ margin-bottom:10px!important;}\n.mb15{ margin-bottom:15px!important;}\n.mb20{ margin-bottom:20px!important;}\n/*float*/\n.fl{ float:left!important;}\n.fr{ float:right!important;}\n.fn{ float:none!important;}\n.pagination{display:inline-block;padding-left:0;margin:18px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:17px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}\nhr {\nheight: 0;\n-moz-box-sizing: content-box;\nbox-sizing: content-box;\nmargin-top: 20px;\nmargin-bottom: 20px;\nborder: 0;\nborder-top: 1px solid #eee;\n}\n"
  },
  {
    "path": "modules/agent/public/css/odometer.css",
    "content": ".odometer.odometer-auto-theme, .odometer.odometer-theme-default {\n  display: -moz-inline-box;\n  -moz-box-orient: vertical;\n  display: inline-block;\n  vertical-align: middle;\n  *vertical-align: auto;\n  position: relative;\n}\n.odometer.odometer-auto-theme, .odometer.odometer-theme-default {\n  *display: inline;\n}\n.odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-default .odometer-digit {\n  display: -moz-inline-box;\n  -moz-box-orient: vertical;\n  display: inline-block;\n  vertical-align: middle;\n  *vertical-align: auto;\n  position: relative;\n}\n.odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-default .odometer-digit {\n  *display: inline;\n}\n.odometer.odometer-auto-theme .odometer-digit .odometer-digit-spacer, .odometer.odometer-theme-default .odometer-digit .odometer-digit-spacer {\n  display: -moz-inline-box;\n  -moz-box-orient: vertical;\n  display: inline-block;\n  vertical-align: middle;\n  *vertical-align: auto;\n  visibility: hidden;\n}\n.odometer.odometer-auto-theme .odometer-digit .odometer-digit-spacer, .odometer.odometer-theme-default .odometer-digit .odometer-digit-spacer {\n  *display: inline;\n}\n.odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-default .odometer-digit .odometer-digit-inner {\n  text-align: left;\n  display: block;\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  overflow: hidden;\n}\n.odometer.odometer-auto-theme .odometer-digit .odometer-ribbon, .odometer.odometer-theme-default .odometer-digit .odometer-ribbon {\n  display: block;\n}\n.odometer.odometer-auto-theme .odometer-digit .odometer-ribbon-inner, .odometer.odometer-theme-default .odometer-digit .odometer-ribbon-inner {\n  display: block;\n}\n.odometer.odometer-auto-theme .odometer-digit .odometer-value, .odometer.odometer-theme-default .odometer-digit .odometer-value {\n  display: block;\n}\n.odometer.odometer-auto-theme .odometer-digit .odometer-value.odometer-last-value, .odometer.odometer-theme-default .odometer-digit .odometer-value.odometer-last-value {\n  position: absolute;\n}\n.odometer.odometer-auto-theme.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-theme-default.odometer-animating-up .odometer-ribbon-inner {\n  -webkit-transition: -webkit-transform 1s;\n  -moz-transition: -moz-transform 1s;\n  -ms-transition: -ms-transform 1s;\n  -o-transition: -o-transform 1s;\n  transition: transform 1s;\n}\n.odometer.odometer-auto-theme.odometer-animating-up.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-default.odometer-animating-up.odometer-animating .odometer-ribbon-inner {\n  -webkit-transform: translateY(-100%);\n  -moz-transform: translateY(-100%);\n  -ms-transform: translateY(-100%);\n  -o-transform: translateY(-100%);\n  transform: translateY(-100%);\n}\n.odometer.odometer-auto-theme.odometer-animating-down .odometer-ribbon-inner, .odometer.odometer-theme-default.odometer-animating-down .odometer-ribbon-inner {\n  -webkit-transform: translateY(-100%);\n  -moz-transform: translateY(-100%);\n  -ms-transform: translateY(-100%);\n  -o-transform: translateY(-100%);\n  transform: translateY(-100%);\n}\n.odometer.odometer-auto-theme.odometer-animating-down.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-default.odometer-animating-down.odometer-animating .odometer-ribbon-inner {\n  -webkit-transition: -webkit-transform 1s;\n  -moz-transition: -moz-transform 1s;\n  -ms-transition: -ms-transform 1s;\n  -o-transition: -o-transform 1s;\n  -o-transition: -o-transform 1s;\n  transition: transform 1s;\n  -webkit-transform: translateY(0);\n  -moz-transform: translateY(0);\n  -ms-transform: translateY(0);\n  -o-transform: translateY(0);\n  transform: translateY(0);\n}\n\n.odometer.odometer-auto-theme, .odometer.odometer-theme-default {\n  font-family: \"Helvetica Neue\", sans-serif;\n  line-height: 1.1em;\n}\n"
  },
  {
    "path": "modules/agent/public/css/pages/dashboard.css",
    "content": "/*------------------------------------------------------------------\nBootstrap Admin Template by EGrappler.com\n------------------------------------------------------------------*/\n\n\n\n/*------------------------------------------------------------------\n[1. Shortcuts / .shortcuts]\n*/\n\n.shortcuts {\n\ttext-align: center;\t\n}\n\n.shortcuts .shortcut { \n\twidth: 22.50%;\n\tdisplay: inline-block;\n\tpadding: 12px 0;\n\tmargin: 0 .9% 1em;\n\tvertical-align: top;\t\n\t\n\ttext-decoration: none;\n\t\n\tbackground: #f9f6f1;\n\t\n\tborder-radius: 5px;\n}\n\n.shortcuts .shortcut .shortcut-icon {\n\tmargin-top: .25em;\n\tmargin-bottom: .25em;\n\t\n\tfont-size: 32px;\n\tcolor: #545454;\n}\n\n.shortcuts .shortcut:hover {\n\tbackground: #00ba8b;\n}\n\n.shortcuts .shortcut:hover span{\n\tcolor: #fff;\n}\n\n.shortcuts .shortcut:hover .shortcut-icon {\n\tcolor: #fff;\n}\n\n.shortcuts .shortcut-label {\n\tdisplay: block;\n\t\n\tfont-weight: 400;\n\tcolor: #545454;\n}\n\n\n\n/*------------------------------------------------------------------\n[2. Stats / .stats]\n*/\n\n.stats {\n\twidth: 100%;\n\tdisplay: table;\n\tpadding: 0 0 0 10px;\n\tmargin-top: .5em;\n\tmargin-bottom: 1.9em;\n}\n\n.stats .stat {\n\tdisplay: table-cell;\n\twidth: 40%;\n\tvertical-align: top;\n\t\n\tfont-size: 11px;\n\tfont-weight: bold;\n\tcolor: #999;\n}\n\n.stat-value {\n\tdisplay: block;\n\tmargin-bottom: .55em;\n\t\n\tfont-size: 30px;\n\tfont-weight: bold;\n\tletter-spacing: -2px;\n\tcolor: #444;\n}\n\n.stat-time {\n\ttext-align: center;\n\tpadding-top: 1.5em;\n}\n\n.stat-time .stat-value {\n\tcolor: #19bc9c;\n\tfont-size: 40px;\n}\n\n.stats #donut-chart {\n\theight: 100px;\n\tmargin-left: -20px;\t\n}\n\n\n\n\n\n/*------------------------------------------------------------------\n[3. News Item / .news-items]\n*/\n\n.news-items {\n\tmargin: 1em 0 0;\n}\n\n.news-items li {\n\tdisplay: table;\n\tpadding: 0 2em 0 1.5em;\n\tpadding-bottom: 1em;\n\tmargin-bottom: 1em;\n\tborder-bottom: 1px dotted #CCC;\n}\n\n.news-items li:last-child { padding-bottom: 0; border: none; }\n\n.news-item-date {\n\tdisplay: table-cell;\n}\n\n.news-item-detail {\n\tdisplay: table-cell;\n}\n\n.news-item-title {\n\tfont-size: 13px;\n\tfont-weight: 600;\n}\n\n.news-item-date {\n\twidth: 75px;\n\tvertical-align: middle;\n\ttext-align: center;\n\t\n}\n\n.news-item-day {\n\tdisplay: block;\n\tmargin-bottom: .25em;\n\t\n\tfont-size: 24px;\n\tcolor: #888;\n}\n\n.news-item-preview {\n\tmargin-bottom: 0;\n\t\n\tcolor: #777;\n}\n\n.news-item-month {\n\tdisplay: block;\n\tpadding-right: 1px;\t\n\t\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: #888;\n}\n\n\n\n/*------------------------------------------------------------------\n[4. Action Table / .action-table]\n*/\n\n.action-table .btn-small {\n\tpadding: 4px 5px 5px;\n\t\n\tfont-size: 10px;\n}\n\n.action-table .td-actions { \n\twidth: 80px; \n\t\n\ttext-align: center; \n}\n\n.action-table .td-actions .btn { \n\tmargin-right: .5em;\t\t\n}\n\t\n.action-table .td-actions .btn:last-child { \n\tmargin-rigth: 0; \t\t\n}\n\t\n\t\n\t\n.big_stats  {\n\twidth: 100%; \n\tdisplay: table;\n\tmargin-top: 1.5em;\n}\n\n.big-stats-container .widget-content {\n\tborder:0;\n}\n\n.big_stats .stat {\n\twidth: 35%;\n\theight: auto;\n\ttext-align: center;\n\tdisplay: table-cell;\n\tpadding: 0 0 1em;\n\tposition: relative;\n\t\n\tborder-right: 1px solid #CCC;\n\tborder-left: 1px solid #FFF;\n}\n\n.big_stats  i { font-size:20px; display:block; line-height: 30px; color:#b2afaa; }\n.big_stats .stat i { font: 20px/2em \"Open Sans\", sans-serif; color:#19bc9c; }\n\nh6.bigstats {\n\tmargin: 20px;\n\tborder-bottom: 1px solid #eee;\n\tpadding-bottom: 20px;\n\tmargin-bottom: 26px;\n}\n\n.big_stats .stat:first-child {\n\tborder-left: none;\n\twidth:33%;\n}\n\n.big_stats .stat:last-child {\n\tborder-right: none;\n\twidth:33%;\n}\n\n.big_stats .stat h4 {\n\tfont-size: 11px;\n\tfont-weight: bold;\n\tcolor: #777;\n\tmargin-bottom: 1.5em;\n}\n\n.big_stats .stat .value {\n\tfont-size: 20px;\n\tfont-weight: bold;\n\tcolor: #545454;\n\tline-height: 1em;\n}\n\n\n\n@media all and (max-width: 950px) and (min-width: 1px) {\n\t\n\t.big_stats {\n\t\tdisplay: block;\n\t\tmargin-bottom: -10px;\n\t}\n\t\n\t.big_stats .stat {\n\t\twidth: 32%;\n\t\tdisplay: block;\n\t\tmargin-bottom: 1em;\n\t\tfloat: left;\n\t}\t\n\t\n\t\n\t\n}\n\n@media (max-width: 767px) {\n\t.big_stats .stat .value {\n\t\tfont-size: 25px;\n\t}\n}\n\t\n\t\n\t\n\t\n@media (max-width: 979px) {\n\t\n\t.shortcuts .shortcut {\n\t\twidth: 31%;\n\t}\n}\n\n\n@media (max-width: 480px) {\n\t\n\t.stats .stat {\n\t\t\n\t\tmargin-bottom: 3em;\n\t}\n\t\n\t.stats .stat .stat-value {\n\t\tmargin-bottom: .15em;\n\t\t\n\t\tfont-size: 20px;\n\t}\n\t\n\t.stats {\n\t\tfloat: left;\n\t\t\n\t\tdisplay: block;\n\t\t\n\t\tmargin-bottom: 0;\n\t}\n\t\n\t#chart-stats {\n\t\tmargin: 2em 0 1em;\t\t\n\t}\n\t\n\t.shortcuts .shortcut {\n\t\twidth: 48%;\n\t}\n}\n\n/* ADDED BY AFAQ */\n.widget-content { padding:0px; }\n.dataTables_length { display:none; }\n.dataTable { margin-bottom:0px; }\n\n.pulse {\n   background:#19bc9c;\n   border:1px solid #19bc9c;\n   color:white;\n}\n\n.pulse-border {\n   border-color:#19bc9c;\n}\n\n.navbar {\n   position:fixed;\n   top:0;\n   z-index:9999999;\n   width:100%;\n}\n\n.subnavbar {\n   position:fixed;\n   top:50px;\n   z-index:9999999;\n   width:100%;\n}\n\n.main {\n   margin-top:130px;\n}\n.dataTables_paginate{ width:100%; text-align:center; margin-top:10px; margin-left:-30px;}\n.dataTables_paginate a{ margin-left:8px;}\n.dataTables_paginate a:hover{ pointer:pointer;}\n.navbar-fixed-top{  margin-left:0px;}\n.widget-search{display: inline-block; vertical-align: middle; margin: 0 6px; width: 200px;}\n"
  },
  {
    "path": "modules/agent/public/css/style.css",
    "content": "/*------------------------------------------------------------------\nBootstrap Admin Template by EGrappler.com\n------------------------------------------------------------------*/\n\n\n\n/*------------------------------------------------------------------\n[1. Global]\n*/\n\n@font-face {\n  font-family: \"Open Sans\";\n  font-style: normal;\n  font-weight: normal;\n  src: url(\"font/OpenSans-Regular-webfont.eot\") format(\"embedded-opentype\"),\n  url(\"font/OpenSans-Regular-webfont.woff\") format(\"woff\"),\n  url(\"font/OpenSans-Regular-webfont.ttf\") format(\"truetype\"),\n  url(\"font/OpenSans-Regular-webfont.svg#OpenSansRegular\") format(\"svg\");\n}\n\nbody {\n\tbackground: #f9f6f1;\n        font: 12px/1.5em \"Open Sans\", sans-serif;\n}\n    \na {\n    cursor: pointer;\n}\n\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: 'Open Sans';\n}\n\n.dropdown .dropdown-menu {\n\t-webkit-border-radius: 6px;\n\t-moz-border-radius: 6px;\n\tborder-radius: 6px;\n}\n\n.btn-icon-only {\n\tpadding-right: 3px;\n\tpadding-left: 3px;\n}\n\n.table td {\n\tvertical-align: middle;\n}\n\n.table-bordered th {\n\tbackground: #E9E9E9;\n\tbackground:-moz-linear-gradient(top, #FAFAFA 0%, #E9E9E9 100%); /* FF3.6+ */\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#FAFAFA), color-stop(100%,#E9E9E9)); /* Chrome,Safari4+ */\n\tbackground:-webkit-linear-gradient(top, #FAFAFA 0%,#E9E9E9 100%); /* Chrome10+,Safari5.1+ */\n\tbackground:-o-linear-gradient(top, #FAFAFA 0%,#E9E9E9 100%); /* Opera11.10+ */\n\tbackground:-ms-linear-gradient(top, #FAFAFA 0%,#E9E9E9 100%); /* IE10+ */\n\tbackground:linear-gradient(top, #FAFAFA 0%,#E9E9E9 100%); /* W3C */\n\tfilter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FAFAFA', endColorstr='#E9E9E9');\n\t-ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#FAFAFA', endColorstr='#E9E9E9')\";\n\t\n\tfont-size: 10px;\n\tcolor: #444;\n\ttext-transform: uppercase;\n}\n\n\n/*------------------------------------------------------------------\n[2. Navbar / .navbar]\n*/\n\n.navbar .container {\n\tposition: relative;\n}\n\n.navbar-inner {\n\tpadding: 7px 0;\n\t\n\tbackground: #00ba8b !important;\n\t\n\t-moz-border-radius: 0;\n\t-webkit-border-radius: 0;\n\tborder-radius: 0;\n}\n\n.navbar-fixed-top {\n\tposition: static;\n}\n\n.navbar .nav a {\n\tfont-size: 11px;\n}\n.navbar .nav>li>a { color:#fff !important;}\n.navbar .brand {\n\tfont-weight: 600;\n\tposition: relative;\n\ttop: 2px;\n}\n\n.navbar .search-query {\n\tbackground-color: #444;\n\twidth: 150px;\n\tfont-size: 11px;\n\tfont-weight: bold;\n}\n\n.navbar .search-query::-webkit-input-placeholder {\n    color: #666;\n}\n\n.navbar .search-query:-moz-placeholder {\n    color: #666;\n}\n\n.navbar-search .search-query { background:#008866; border:0; color:#fff; line-height:normal;}\n\n\n/*------------------------------------------------------------------\n[3. Subnavbar / .subnavbar]\n*/\n\n.subnavbar {\n    \tmargin-bottom: 2.5em;\n    }\n    \n.subnavbar-inner {\n\theight: 60px;\n\tbackground: #fff;\n\tborder-bottom: 1px solid #d6d6d6;\n}\n\n.subnavbar .container > ul {\n\tdisplay: inline-block;\n\t\n\theight: 80px;\n\tpadding: 0;\n\tmargin: 0;\n\t\n}\n\n.subnavbar .container > ul > li {\n\tfloat: left;\n\t\n\tmin-width: 90px;\n\theight: 60px;\n\tpadding: 0;\n\tmargin: 0;\n\t\n\ttext-align: center;\n\tlist-style: none;\n\t\n\tborder-left: 1px solid #d9d9d9;\n\t\n\t\n}\n\n.subnavbar .container > ul > li > a {\n\tdisplay: block;\n\t\n\theight: 100%;\n\tpadding: 0 15px;\n\t\n\tfont-size: 12px;\n\tfont-weight: bold;\n\tcolor: #b2afaa;\n}\n\n.subnavbar .container > ul > li > a:hover {\n\tcolor: #888;\n\ttext-decoration: none;\n}\n\n.subnavbar .container > ul > li > a > i {\n\tdisplay: inline-block;\n\t\n\twidth: 24px;\n\theight: 24px;\n\tmargin-top: 11px;\n\tmargin-bottom: -3px;\n\tfont-size: 20px;\n}\n\n.subnavbar .container > ul > li > a > span {\n\tdisplay: block;\n\t\n}\n\n\n.subnavbar .container > ul > li:hover > a {\n\t\n\tborder-bottom:3px solid #ff7f74;\n\tcolor: #383838;\n}\n    \n\n.subnavbar .dropdown .dropdown-menu a {\n\tfont-size: 12px;\n}\n\n    \n.subnavbar .dropdown .dropdown-menu {\n    text-align: left;\n    \t\n\t-webkit-border-top-left-radius: 0;\n\t-webkit-border-top-right-radius: 0;\n\t-moz-border-radius-topleft: 0;\n\t-moz-border-radius-topright: 0;\n\tborder-top-left-radius: 0;\n\tborder-top-right-radius: 0;\n}\n    \n    \n    \n.subnavbar .dropdown-menu::before {\n\tcontent: '';\n\tdisplay: inline-block;\n\tborder-left: 7px solid transparent;\n\tborder-right: 7px solid transparent;\n\tborder-bottom: 7px solid #CCC;\n\tborder-bottom-color: rgba(0, 0, 0, 0.2);\n\tposition: absolute;\n\ttop: -7px;\n\tleft: 9px;\n}\n\n.subnavbar .dropdown-menu::after {\n\tcontent: '';\n\tdisplay: inline-block;\n\tborder-left: 6px solid transparent;\n\tborder-right: 6px solid transparent;\n\tborder-bottom: 6px solid white;\n\tposition: absolute;\n\ttop: -6px;\n\tleft: 10px;\n}\n\n\n.subnavbar .caret {\n\tmargin-top: 4px;\n\t\n\tborder-top-color: white;\n\tborder-bottom-color: white;\n}\n\n.subnavbar .dropdown.open .caret {\n\tdisplay: none;\n}\n\n\n\n\n\n/*------------------------------------------------------------------\n[4. Main / .main]\n\n\n.main {\n\tpadding-bottom: 2em;\n\t\n\tborder-bottom: 1px solid #000;\n}\n*/\n\n\n/*------------------------------------------------------------------\n[5. Extra / .extra]\n*/\n\n.extra {\n\n\tborder-top: 1px solid #585858;\n\tborder-bottom: 1px solid #000;\n\n}\n\n.extra-inner {\n\tpadding: 20px 0;\n\t\n\tfont-size: 11px;\n\tcolor: #BBB;\n\t\n\tbackground: #1A1A1A;\n}\n\n.extra a {\n\tcolor: #666;\n}\n\n.extra h4 {\n\tmargin-bottom: 1em;\n\t\n\tfont-weight: 400;\n}\n\n.extra ul {\n\tpadding: 0;\n\tmargin: 0;\n}\n\n.extra li {\n\tmargin-bottom: .6em;\n\t\n\tlist-style: none;\n}\n\n\n\n\n/*------------------------------------------------------------------\n[6. Footer/ .footer]\n*/\n\n.footer {\n\tmargin-top: 0;\n\t\n\tborder-top: 1px solid #292929;\n}\n\n.footer-inner {\n\tpadding: 15px 0;\n\t\n\tfont-size: 12px;\n\tbackground: #111;\n\tcolor: #999;\n}\n\n.footer a {\n\tcolor: #999;\n}\n\n.footer a:hover {\n\tcolor: #FFF;\n\ttext-decoration: none;\n}\n\n\n/*------------------------------------------------------------------\n[6. Widget / .widget]\n*/\n\n.widget {\n\t\n\tposition: relative;\n\tclear: both;\n\t\n\twidth: auto;\n\t\n\tmargin-bottom: 2em;\n\t\t\n\toverflow: hidden;\n}\n\t\n.widget-header {\n\tposition: relative;\n        cursor: move;\t\n\theight: 40px;\n\tline-height: 40px;\n\t\n\tbackground: #f9f6f1;\n\tbackground:-moz-linear-gradient(top, #f9f6f1 0%, #f2efea 100%); /* FF3.6+ */\n\tbackground:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f9f6f1), color-stop(100%,#f2efea)); /* Chrome,Safari4+ */\n\tbackground:-webkit-linear-gradient(top, #f9f6f1 0%,#f2efea 100%); /* Chrome10+,Safari5.1+ */\n\tbackground:-o-linear-gradient(top, #f9f6f1 0%,#f2efea 100%); /* Opera11.10+ */\n\tbackground:-ms-linear-gradient(top, #f9f6f1 0%,#f2efea 100%); /* IE10+ */\n\tbackground:linear-gradient(top, #f9f6f1 0%,#f2efea 100%); /* W3C */\n\tfilter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f6f1', endColorstr='#f2efea');\n\t-ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f6f1', endColorstr='#f2efea')\";\n\t\n\t\n\tborder: 1px solid #d6d6d6;\n\t\n\t\n\t-webkit-background-clip: padding-box;\n}\t\n\t\n.widget-header h3 {\n\tposition: relative;\n\ttop: 2px;\n\tleft: 10px;\n\t\n\tdisplay: inline-block;\n\tmargin-right: 3em;\n\t\t\n\tfont-size: 14px;\n\tfont-weight: 800;\n\tcolor: #525252;\n\tline-height: 18px;\n\t\n\ttext-shadow: 1px 1px 2px rgba(255,255,255,.5);\n}\n\t\n.widget-header [class^=\"icon-\"], .widget-header [class*=\" icon-\"] {\n\t\t\n\tdisplay: inline-block;\n\tmargin-left: 13px;\n\tmargin-right: -2px;\n\t\t\t\n\tfont-size: 16px;\n\tcolor: #555;\n\tvertical-align: middle;\n}\n\n.widget-content {\n\tpadding: 20px 15px 15px;\n\tbackground: #FFF;\n\t\n\t\n\tborder: 1px solid #D5D5D5;\n\t\n\t-moz-border-radius: 5px;\n\t-webkit-border-radius: 5px;\n\tborder-radius: 5px;\n}\n\n.widget-header+.widget-content {\n\tborder-top: none;\n\t\n\t-webkit-border-top-left-radius: 0;\n\t-webkit-border-top-right-radius: 0;\n\t-moz-border-radius-topleft: 0;\n\t-moz-border-radius-topright: 0;\n\tborder-top-left-radius: 0;\n\tborder-top-right-radius: 0;\n}\n\n.widget-nopad .widget-content {\n\tpadding: 0;\n}\n\n/* Widget Content Clearfix */\t\n.widget-content:before,\n.widget-content:after {\n    content:\"\";\n    display:table;\n}\n\n.widget-content:after {\n    clear:both;\n}\n\n/* For IE 6/7 (trigger hasLayout) */\n.widget-content {\n    zoom:1;\n}\n\n/* Widget Table */\n\n.widget-table .widget-content {\n\tpadding: 0;\n}\n\n.widget-table .table {\n\tmargin-bottom: 0;\n\t\n\tborder: none;\n}\n\n.widget-table .table tr td:first-child {\n\tborder-left: none;\n}\n\n.widget-table .table tr th:first-child {\n\tborder-left: none;\n}\n\n\n/* Widget Plain */\n\n.widget-plain {\n\t\n\tbackground: transparent;\n\t\n\tborder: none;\n}\n\n.widget-plain .widget-content {\n\tpadding: 0;\n\t\n\tbackground: transparent;\n\t\n\tborder: none;\n}\n\n\n/* Widget Box */\n\n.widget-box {\t\n\t\n}\n\n.widget-box .widget-content {\t\n\tbackground: #E3E3E3;\t\n\tbackground: #FFF;\n}\n\n\n\n/*------------------------------------------------------------------\n[7. Error / .error-container]\n*/\n\n.error-container {\n\tmargin-top: 4em;\n\tmargin-bottom: 4em;\n\ttext-align: center;\n}\n\n.error-container h1 {\n\tmargin-bottom: .5em;\n\t\n\tfont-size: 120px;\n\tline-height: 1em;\n}\n\n.error-container h2 {\n\tmargin-bottom: .75em;\n\tfont-size: 28px;\n}\n\n.error-container .error-details {\n\tmargin-bottom: 1.5em;\n\t\n\tfont-size: 16px;\n}\n\n.error-container .error-actions a {\n\tmargin: 0 .5em;\n}\n\n\n\n/* Message layout */\n\n\nul.messages_layout {\n\tposition: relative;\n\tmargin: 0;\n\tpadding: 0\n}\nul.messages_layout li {\n\tfloat: left;\n\tlist-style: none;\n\tposition: relative\n}\nul.messages_layout li.left {\n\tpadding-left: 75px\n}\nul.messages_layout li.right {\n\tpadding-right: 75px\n}\nul.messages_layout li.right .avatar {\n\tright: 0;\n\tleft: auto\n}\nul.messages_layout li.right .message_wrap .arrow {\n\tright: -12px;\n\tleft: auto;\n\tbackground-position: 0 -213px;\n\theight: 15px;\n\twidth: 12px\n}\nul.messages_layout li.by_myself .message_wrap {\n\tborder: 1px solid #b3cdf8\n}\nul.messages_layout li.by_myself .message_wrap .info a.name {\n\tcolor: #4a8cf7\n}\nul.messages_layout li a.avatar {\n\tposition: absolute;\n\tleft: 0;\n\ttop: 0\n}\nul.messages_layout li a.avatar img {\n\t-webkit-border-radius: 5px;\n\t-moz-border-radius: 5px;\n\tborder-radius: 5px\n}\nul.messages_layout li .message_wrap {\n\t-webkit-border-radius: 3px;\n\t-moz-border-radius: 3px;\n\tborder-radius: 3px;\n\tposition: relative;\n\tborder: 1px solid #e9e9e9;\n\tpadding: 10px;\n\tborder: 1px solid #cbcbcb;\n\tmargin-bottom: 20px;\n\tfloat: left;\n\tbackground: #fefefe;\n\t-webkit-box-shadow: rgba(0,0,0,0.1) 0 1px 0px;\n\t-moz-box-shadow: rgba(0,0,0,0.1) 0 1px 0px;\n\tbox-shadow: rgba(0,0,0,0.1) 0 1px 0px\n}\nul.messages_layout li .message_wrap .arrow {\n\tbackground-position: 0 -228px;\n\theight: 15px;\n\twidth: 12px;\n\theight: 15px;\n\twidth: 12px;\n\tposition: absolute;\n\tleft: -12px;\n\ttop: 13px\n}\nul.messages_layout li .message_wrap .info {\n\tfloat: left;\n\twidth: 100%;\n\tborder-bottom: 1px solid #fff;\n\tline-height: 23px\n}\nul.messages_layout li .message_wrap .info .name {\n\tfloat: left;\n\tfont-weight: bold;\n\tcolor: #483734\n}\nul.messages_layout li .message_wrap .info .time {\n\tfloat: left;\n\tfont-size: 11px;\n\tmargin-left: 6px\n}\nul.messages_layout li .message_wrap .text {\n\tfloat: left;\n\twidth: 100%;\n\tborder-top: 1px solid #cfcfcf;\n\tpadding-top: 5px\n}\n\nul.messages_layout .dropdown-menu  li{ width:100%; font-size:11px;}\n\n\n/* Full Calendar */\n\n.fc {\n\tdirection: ltr;\n\ttext-align: left;\n\tposition: relative\n}\n.fc table {\n\tborder-collapse: collapse;\n\tborder-spacing: 0\n}\nhtml .fc, .fc table {\n\tfont-size: 1em\n}\n.fc td, .fc th {\n\tpadding: 0;\n\tvertical-align: top\n}\n.fc-header td {\n\twhite-space: nowrap;\n\tbackground: none\n}\n.fc-header-left {\n\twidth: 100%;\n\ttext-align: left;\n\tposition: absolute;\n\tleft: 0;\n\ttop: 6px\n}\n.fc-header-left .fc-button {\n\tmargin: 0;\n\tposition: relative\n}\n.fc-header-left .fc-button-prev, .fc-header-left .fc-button-next {\n\tfloat: left;\n\tborder: none;\n\tpadding: 14px 10px;\n\topacity: 0.5\n}\n.fc-header-left .fc-button-prev .fc-button-inner, .fc-header-left .fc-button-next .fc-button-inner {\n\tborder: none\n}\n.fc-header-left .fc-button-prev .fc-button-inner .fc-button-content, .fc-header-left .fc-button-next .fc-button-inner .fc-button-content {\n\tdisplay: none\n}\n.fc-header-left .fc-button-prev.fc-state-hover, .fc-header-left .fc-button-next.fc-state-hover {\n\topacity: 1\n}\n.fc-header-left .fc-button-prev.fc-state-down, .fc-header-left .fc-button-next.fc-state-down {\n\tbackground: none !important;\n\tmargin-top: -1px\n}\n.fc-header-left .fc-button-prev .fc-button-inner {\n\tbackground-position: 0 -351px;\n\theight: 16px;\n\twidth: 11px\n}\n.fc-header-left .fc-button-next {\n\tfloat: right\n}\n.fc-header-left .fc-button-next .fc-button-inner {\n\tbackground-position: 0 -367px;\n\theight: 16px;\n\twidth: 11px\n}\n.fc-header-center {\n\ttext-align: center\n}\n.fc-header-right {\n\ttext-align: right;\n\tposition: absolute;\n\ttop: -34px;\n\tright: 10px\n}\n.fc-header-title {\n\tdisplay: inline-block;\n\tvertical-align: top\n}\n.fc-header-title h2 {\n\tmargin-top: 0;\n\twhite-space: nowrap;\n\tfont-size: 1.1rem;\n\tcolor: #6C737F;\n\tline-height: 55px;\n}\n.fc .fc-header-space {\n\tpadding-left: 10px\n}\n.fc-header .fc-button {\n\tmargin-bottom: 1em;\n\tvertical-align: top\n}\n.fc-header .fc-button {\n\tmargin-right: -1px\n}\n.fc-header .fc-corner-right {\n\tmargin-right: 1px\n}\n.fc-header .ui-corner-right {\n\tmargin-right: 0\n}\n.fc-header .fc-state-hover, .fc-header .ui-state-hover {\n\tz-index: 2\n}\n.fc-header .fc-state-down {\n\tz-index: 3\n}\n.fc-header .fc-state-active, .fc-header .ui-state-active {\n\tz-index: 4\n}\n.fc-content {\n\tclear: both;\n\tbackground: #f9f9f9\n}\n.fc-view {\n\twidth: 100%;\n\toverflow: hidden\n}\n.fc-view thead {\n\tbackground:#e9ecf1;\n\tline-height: 35px\n}\n.fc-widget-header, .fc-widget-content {\n\tborder: 1px solid #ccc\n}\n.fc-state-highlight {\n\tbackground: #F4F3E6\n}\n.fc-cell-overlay {\n\tbackground: #9cf;\n\topacity: .2;\n\tfilter: alpha(opacity=20)\n}\n.fc-button {\n\tposition: relative;\n\tdisplay: inline-block;\n\tcursor: pointer\n}\n.fc-button-today{margin-top: 8px !important;}\n.fc-state-default {\n\tborder-style: solid;\n\tborder-width: 1px 0\n}\n.fc-button-inner {\n\tposition: relative;\n\tfloat: left;\n\toverflow: hidden\n}\n.fc-state-default .fc-button-inner {\n\tborder-style: solid;\n\tborder-width: 0 1px\n}\n.fc-button-content {\n\tposition: relative;\n\tfloat: left;\n\theight: 1.9em;\n\tline-height: 1.9em;\n\tpadding: 0 .6em;\n\twhite-space: nowrap\n}\n.fc-button-content .fc-icon-wrap {\n\tposition: relative;\n\tfloat: left;\n\ttop: 50%\n}\n.fc-button-content .ui-icon {\n\tposition: relative;\n\tfloat: left;\n\tmargin-top: -50%;\n*margin-top:0;\n*top:-50%\n}\n.fc-state-default .fc-button-effect {\n\tposition: absolute;\n\ttop: 50%;\n\tleft: 0\n}\n.fc-state-default .fc-button-effect span {\n\tposition: absolute;\n\ttop: -100px;\n\tleft: 0;\n\twidth: 500px;\n\theight: 100px;\n\tborder-width: 100px 0 0 1px;\n\tborder-style: solid;\n\tborder-color: #fff;\n\tbackground: #444;\n\topacity: .09;\n\tfilter: alpha(opacity=9)\n}\n.fc-state-default, .fc-state-default .fc-button-inner {\n\tborder-style: solid;\n\tborder-color: #ccc #bbb #aaa;\n\tcolor: #000\n}\n.fc-state-hover, .fc-state-hover .fc-button-inner {\n\tborder-color: #999\n}\n.fc-state-down {\n\tborder-color: #555;\n\tbackground: #777\n}\n.fc-state-active, .fc-state-active .fc-button-inner {\n\tborder-color: #555;\n\tbackground: #777;\n\tcolor: #fff\n}\n.fc-state-disabled, .fc-state-disabled .fc-button-inner {\n\tcolor: #999;\n\tborder-color: #ddd\n}\n.fc-state-disabled {\n\tcursor: default\n}\n.fc-state-disabled .fc-button-effect {\n\tdisplay: none\n}\n.fc-event {\n\tborder-style: solid;\n\tborder-width: 0;\n\tfont-size: .85em;\n\tcursor: default\n}\na.fc-event, .fc-event-draggable {\n\tcursor: pointer\n}\na.fc-event {\n\ttext-decoration: none\n}\n.fc-rtl .fc-event {\n\ttext-align: right\n}\n.fc-event-skin {\n\tborder-color: #3f85f5;\n\tbackground-color: #5e96ea;\n\tcolor: #fff\n}\n.fc-event-inner {\n\tposition: relative;\n\twidth: 100%;\n\theight: 100%;\n\tborder-style: solid;\n\tborder-width: 0;\n\toverflow: hidden\n}\n.fc-event-time, .fc-event-title {\n\tpadding: 0 1px\n}\n.fc .ui-resizable-handle {\n\tdisplay: block;\n\tposition: absolute;\n\tz-index: 99999;\n\toverflow: hidden;\n\tfont-size: 300%;\n\tline-height: 50%\n}\n.fc-event-hori {\n\tborder-width: 1px 0;\n\tmargin-bottom: 1px\n}\n.fc-event-hori .ui-resizable-e {\n\ttop: 0 !important;\n\tright: -3px !important;\n\twidth: 7px !important;\n\theight: 100% !important;\n\tcursor: e-resize\n}\n.fc-event-hori .ui-resizable-w {\n\ttop: 0 !important;\n\tleft: -3px !important;\n\twidth: 7px !important;\n\theight: 100% !important;\n\tcursor: w-resize\n}\n.fc-event-hori .ui-resizable-handle {\n\t_padding-bottom: 14px\n}\n.fc-corner-left {\n\tmargin-left: 1px\n}\n.fc-corner-left .fc-button-inner, .fc-corner-left .fc-event-inner {\n\tmargin-left: -1px\n}\n.fc-corner-right {\n\tmargin-right: 1px\n}\n.fc-corner-right .fc-button-inner, .fc-corner-right .fc-event-inner {\n\tmargin-right: -1px\n}\n.fc-corner-top {\n\tmargin-top: 1px\n}\n.fc-corner-top .fc-event-inner {\n\tmargin-top: -1px\n}\n.fc-corner-bottom {\n\tmargin-bottom: 1px\n}\n.fc-corner-bottom .fc-event-inner {\n\tmargin-bottom: -1px\n}\n.fc-corner-left .fc-event-inner {\n\tborder-left-width: 1px\n}\n.fc-corner-right .fc-event-inner {\n\tborder-right-width: 1px\n}\n.fc-corner-top .fc-event-inner {\n\tborder-top-width: 1px\n}\n.fc-corner-bottom .fc-event-inner {\n\tborder-bottom-width: 1px\n}\ntable.fc-border-separate {\n\tborder-collapse: separate\n}\n.fc-border-separate th, .fc-border-separate td {\n\tborder-width: 1px 0 0 1px\n}\n.fc-border-separate th.fc-last, .fc-border-separate td.fc-last {\n\tborder-right-width: 1px\n}\n.fc-border-separate tr.fc-last th, .fc-border-separate tr.fc-last td {\n\tborder-bottom-width: 0px\n}\n.fc-first {\n\tborder-left-width: 0 !important\n}\n.fc-last {\n\tborder-right-width: 0 !important\n}\n.fc-grid th {\n\ttext-align: center\n}\n.fc-grid .fc-day-number {\n\tfloat: right;\n\tpadding: 0 2px\n}\n.fc-grid .fc-other-month .fc-day-number {\n\topacity: 0.3;\n\tfilter: alpha(opacity=30)\n}\n.fc-grid .fc-day-content {\n\tclear: both;\n\tpadding: 2px 2px 1px\n}\n.fc-grid .fc-event-time {\n\tfont-weight: bold\n}\n.fc-rtl .fc-grid .fc-day-number {\n\tfloat: left\n}\n.fc-rtl .fc-grid .fc-event-time {\n\tfloat: right\n}\n.fc-agenda table {\n\tborder-collapse: separate\n}\n.fc-agenda-days th {\n\ttext-align: center\n}\n.fc-agenda .fc-agenda-axis {\n\twidth: 60px !important;\n\tpadding: 0 4px;\n\tvertical-align: middle;\n\ttext-align: right;\n\twhite-space: nowrap;\n\tfont-weight: normal\n}\n.fc-agenda .fc-day-content {\n\tpadding: 2px 2px 1px\n}\n.fc-agenda-days .fc-agenda-axis {\n\tborder-right-width: 1px\n}\n.fc-agenda-days .fc-col0 {\n\tborder-left-width: 0\n}\n.fc-agenda-allday th {\n\tborder-width: 0 1px\n}\n.fc-agenda-allday .fc-day-content {\n\tmin-height: 34px;\n\t_height: 34px\n}\n.fc-agenda-divider-inner {\n\theight: 2px;\n\toverflow: hidden\n}\n.fc-widget-header .fc-agenda-divider-inner {\n\tbackground: #eee\n}\n.fc-agenda-slots th {\n\tborder-width: 1px 1px 0\n}\n.fc-agenda-slots td {\n\tborder-width: 1px 0 0;\n\tbackground: none\n}\n.fc-agenda-slots td div {\n\theight: 20px\n}\n.fc-agenda-slots tr.fc-slot0 th, .fc-agenda-slots tr.fc-slot0 td {\n\tborder-top-width: 0\n}\n.fc-agenda-slots tr.fc-minor th, .fc-agenda-slots tr.fc-minor td {\n\tborder-top-style: dotted\n}\n.fc-agenda-slots tr.fc-minor th.ui-widget-header {\n*border-top-style:solid\n}\n.fc-event-vert {\n\tborder-width: 0 1px\n}\n.fc-event-vert .fc-event-head, .fc-event-vert .fc-event-content {\n\tposition: relative;\n\tz-index: 2;\n\twidth: 100%;\n\toverflow: hidden\n}\n.fc-event-vert .fc-event-time {\n\twhite-space: nowrap;\n\tfont-size: 10px\n}\n.fc-event-vert .fc-event-bg {\n\tposition: absolute;\n\tz-index: 1;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tbackground: #fff;\n\topacity: .3;\n\tfilter: alpha(opacity=30)\n}\n.fc .ui-draggable-dragging .fc-event-bg, .fc-select-helper .fc-event-bg {\n\tdisplay: none\\9\n}\n.fc-event-vert .ui-resizable-s {\n\tbottom: 0 !important;\n\twidth: 100% !important;\n\theight: 8px !important;\n\toverflow: hidden !important;\n\tline-height: 8px !important;\n\tfont-size: 11px !important;\n\tfont-family: monospace;\n\ttext-align: center;\n\tcursor: s-resize\n}\n.fc-agenda .ui-resizable-resizing {\n\t_overflow: hidden\n}\n.fc-header-left .fc-button-prev .fc-button-inner {background: url('../img/icons-sa7c41345d9.png') no-repeat; background-position: 0 -351px;\nheight: 16px;\nwidth: 11px;}\n\n.fc-header-left .fc-button-next .fc-button-inner {background: url('../img/icons-sa7c41345d9.png') no-repeat; background-position: 0 -367px;\nheight: 16px;\nwidth: 11px;}\n\n/*------------------------------------------------------------------\n[8. Miscellaneous]\n*/\n\n.chart-holder {\n\twidth: 100%;\n\theight: 250px;\n}\n\n.dropdown-menu li>a:hover, .dropdown-menu .active>a, .dropdown-menu .active>a:hover { background:#00ba8b;}\n\n.accordion-heading { background:#e5e5e5;  }\n.accordion-heading a { color:#545454; text-decoration:none; font-weight:bold; }\n\n.btn-facebook-alt i {\n\tcolor: #23386a;\n}\n.btn-twitter-alt i {\n\tcolor: #0098d0;\n}\n.btn-google-alt i {\n\tcolor: #b6362d;\n}\n.btn-linkedin-alt i {\n\tcolor: #0073b2;\n}\n.btn-pinterest-alt i {\n\tcolor: #ab171e;\n}\n.btn-github-alt i {\n\tcolor: #333;\n}\n\n.all-icons li { list-style:none;}\n\n.ML0 { margin-left:0}\n.MR0 { margin-right:0;}\n\n.paginate_active { text-decoration: underline; }\n\n#refresh-ispeed .icon-refresh, #refresh-ping .icon-refresh, #refresh-bandwidth .icon-refresh {\n\tmargin: 0;\n}\n\n/*------------------------------------------------------------------\n[1. Max Width: 480px]\n*/\n\n@media (max-width: 480px) {\n\t\n\t.error-container h1 {\n\t\tfont-size: 72px;\n\t}\n\t\n}\n\n\n\n\n\n/*------------------------------------------------------------------\n[1. Max Width: 767px]\n*/\n\n@media (max-width: 767px) {\n    \t\n\t#main {\n\t\tpadding: 0 10px;\n\t\tmargin-right: -20px;\n\t\tmargin-left: -20px;\t\n\t}\n\t\n\t\n\t.subnavbar {\n\t\tmargin-left: -20px;\n\t\tmargin-right: -20px;\t\n\t}\n\t\n\t\n\t.subnavbar-inner {\n\t\theight: auto;\n\t}\n\t\n\t.subnavbar .container > ul {\n\t\twidth: 100%;\n\t\theight: auto;\n\t\t\n\t\tborder: none;\n\t}\n\t\n\t.subnavbar .container > ul > li {\n\t\twidth: 33%;\n\t\theight: 70px;\n\t\tmargin-bottom: 0;\n\t\t\n\t\tborder: none;\n\t}\n\t\n    \n    \n    .subnavbar .container > ul > li.active > a {\n\t\tfont-size: 11px;\n    \tbackground: transparent;\n    }\n\t\n\t.subnavbar .container > ul > li > a > i {\t\n\t\tdisplay: inline-block;\t\n\t\tmargin-bottom: 0;\n\t\t\n\t\tfont-size: 20px;\n\t}\n\t\n\t\n\t.subnavbar-open-right .dropdown-menu {\n\t\tleft: auto;\n\t\tright: 0;\n\t}\n\t\n\t.subnavbar-open-right .dropdown-menu:before {\n\t\tleft: auto;\n\t\tright: 12px;\n\t}\n\t.subnavbar-open-right .dropdown-menu:after {\n\t\tleft: auto;\n\t\tright: 13px;\n\t}\n\t\n\t.extra {\n\t\tmargin-right: -20px;\n\t\tmargin-left: -20px;\n\t}\n\t\n\t.extra .container {\n\t\tpadding: 0 20px;\n\t}\n\t\n\t.footer {\n\t\tmargin-right: -20px;\n\t\tmargin-left: -20px;\n\t}\n\t\n\t.footer .container {\n\t\tpadding: 0 20px;\n\t}\n\t\n\t.footer .footer-terms {\n\t\ttext-align: left;\n\t}\n\t\n\t.footer .footer-terms a {\n\t\tmargin-left: 0;\n\t\tmargin-right: 1em;\n\t}\n\n}\n    \n\n\n\n\n/*------------------------------------------------------------------\n[2. Max Width: 979px]\n*/\n\n@media (max-width: 979px) {\n\t\n\t.navbar-fixed-top {\n\t\tposition: static;\n\t\t\n\t\tmargin-bottom: 0;\n\t}\n\t\n\t.subnavbar {\n\t}\n\t\n\t.subnavbar .container {\t\t\n\t\twidth: auto;\n\t}\n\n\t.widget-header {\n\t\theight: 100%;\n\t}\n\n\t.widget-header h3 {\n\t\tmargin-right: 1em;\n\t}\n\n\t.js-refresh-info {\n\t\tmargin-left: 25px;\n\t}\n}\n\n\n\n\n\n\n/*------------------------------------------------------------------\n[3. Max Width: 1199px]\n*/\n\n@media (max-width: 1199px) {\n\t.navbar .search-query {\n\t\twidth: 200px;\n\t}\n\n\t.widget-header {\n\t\theight: 100%;\n\t}\n\n\t.js-refresh-info {\n\t\tmargin-left: 25px;\n\t}\t\n}\n\n/* ----------------------------------------\n\tSubnavbar CSS fix/work-around\n*/\n\n.container.nav-collapse.in {\n    overflow:visible;\n}\n.btn-navbar {\n    margin-top:-38px;\n}\n\n/*------------------------------------------------------------------\n\tgeneral-info widget specific style\n*/\n\n#general-info-widget .general-title {\n\tfont-weight: bold;\n}\n\n#general-info-widget .general-title:after {\n\tcontent:\":\";\n}\n\n#general-info-widget .widget-content {\n\tpadding:5px;\n}\n\n#general-info-widget .widget-content div {\n\tmargin-bottom:5px;\n}\n\nfooter {\nborder-top: 1px solid #D8D7CF;\nclear: both;\ncolor: #9A9994;\nfont-size: 12px;\nline-height: 15.4px;\nmargin-top: 15px;\noverflow: hidden;\npadding: 20px 0 40px;\n}\nfooter .site-source {\nbackground: url(\"../img/code.png\") no-repeat scroll 0 2px transparent;\nfloat: left;\npadding-left: 46px;\n}\nfooter .sfc-member {float: right;text-align: right;}\nfooter a {color: #403F3C;}\n"
  },
  {
    "path": "modules/agent/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n    <head>\n        <title>linux-dash : Server Monitoring Web Dashboard</title>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n        <meta name=\"description\" content=\"Monitor your Linux server through a simple web dashboard. Open source and free!\">\n        <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n        <link rel=\"shortcut icon\" href=\"img/favicon.ico\" type=\"image/x-icon\">\n        <link rel=\"icon\" href=\"img/favicon.ico\" type=\"image/x-icon\">\n        <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\" type=\"text/css\">\n        <link href=\"css/bootstrap-responsive.min.css\" rel=\"stylesheet\" type=\"text/css\">\n        <link href=\"css/font-awesome/css/font-awesome.min.css\" rel=\"stylesheet\" type=\"text/css\">\n        <link href=\"css/style.css\" rel=\"stylesheet\" type=\"text/css\">\n        <link href=\"css/pages/dashboard.css\" rel=\"stylesheet\" type=\"text/css\">\n        <link href=\"css/odometer.css\" rel=\"stylesheet\" type=\"text/css\">\n        <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->\n        <!--[if lt IE 9]>\n          <script src=\"https://html5shim.googlecode.com/svn/trunk/html5.js\"></script>\n        <![endif]-->\n    </head>\n    <body>\n        <div class=\"navbar navbar-fixed-top\">\n            <div class=\"navbar-inner\">\n                <div class=\"container\">\n                    <a class=\"brand\" href=\"./\">Falcon-Agent</a>\n                    <div class=\"nav-collapse\">\n        \t\t        <ul class=\"nav pull-right\">\n                            <li>\n                                <a target=\"_blank\" href=\"https://github.com/open-falcon/agent\">\n                                    <i class=\"lead icon-github-sign\"></i> \n            \t\t\t\t        <span class=\"lead\">Contribute on GitHub</span>\n            \t\t\t        </a>\n                            </li>\n                        </ul>\n                    </div>\n                </div>\n            </div>\n        </div>\n        <div class=\"subnavbar\">\n            <div class=\"subnavbar-inner\">\n\n \t        <a class=\"btn btn-navbar btn-info visible-phone\" data-toggle=\"collapse\" data-target=\".nav-collapse\">\n        \t    <span class=\"icon-bar\"></span>\n        \t    <span class=\"icon-bar\"></span>\n        \t    <span class=\"icon-bar\"></span>\n      \t\t</a>\n\n                <div class=\"container nav-collapse\">\n\n                    <ul class=\"mainnav\">\n                        <li>\n                            <a class=\"js-smoothscroll\" href=\"#refresh-os\"><i class=\"icon-info-sign\"></i><span>General</span></a>\n                        </li>\n                        <li>\n                            <a class=\"js-smoothscroll\" href=\"#refresh-load\"><i class=\"icon-laptop\"></i><span>Loadavg</span></a>\n                        </li>\n                        <li>\n                            <a class=\"js-smoothscroll\" href=\"#refresh-ram\"><i class=\"icon-dashboard\"></i><span>Ram</span></a>\n                        </li>\n                        <li>\n                            <a class=\"js-smoothscroll\" href=\"#refresh-df\"><i class=\"icon-list-alt\"></i><span>Disk</span></a>\n                        </li>\n                         <li>\n                            <a class=\"js-smoothscroll\" href=\"#refresh-diskstats\"><i class=\"icon-exchange\"></i><span>DiskIO</span></a>\n                        </li>\n                        <li>\n                            <a class=\"js-smoothscroll\" href=\"#refresh-cpu\"><i class=\"icon-list-alt\"></i><span>Cpu</span></a>\n                        </li>\n                    </ul>\n\n                </div><!-- /container -->\n            </div><!-- /subnavbar-inner -->\n        </div><!-- /subnavbar -->\n        <div class=\"main\">\n            <div class=\"main-inner\">\n                <div class=\"container\">\n                    <div class=\"lead\" style=\"text-align: center;\">\n                        <div class=\"btn icon-refresh js-refresh-info\" data-title=\"Refresh all widgets!\" data-toggle=\"tooltip\" id=\"refresh-all\"></div>\n                        <div>\n                            A simple web dashboard to monitor your server.\n                        </div>\n                    </div>\n                    <div id=\"widgets\" class=\"\">\n\n                    <div class=\"row\">\n                        <div class=\"span3\">\n                            <div id=\"general-info-widget\" class=\"widget widget-table action-table\">\n                                <div class=\"widget-header\">\n                                    <i class=\"icon-info-sign\"></i>\n                                    <h3>\n                                        General Info\n                                    </h3>\n                                    <div id=\"refresh-os\" class=\"btn icon-refresh js-refresh-info\"></div>\n                                </div><!-- /widget-header -->\n                                <div class=\"widget-content\">\n                                    <div class=\"general-info-item\">\n                                        <span class=\"general-title\">Kernel Version</span>\n                                        <span class=\"general-data\" id=\"os-info\"></span>\n                                    </div>\n                                    <div class=\"general-info-item\">\n                                        <span class=\"general-title\">Uptime</span>\n                                        <span id=\"os-uptime\"></span>\n                                    </div>\n                                    <div class=\"general-info-item\">\n                                        <span class=\"general-title\">Server Time</span>\n                                        <span id=\"os-time\"></span>\n                                    </div>\n                                    <div class=\"general-info-item\">\n                                        <span class=\"general-title\">Hostname</span>\n                                        <span id=\"os-hostname\"></span>\n                                    </div>\n                                    <div class=\"general-info-item\">\n                                        <span class=\"general-title\">Agent Version</span>\n                                        <span id=\"agent-version\"></span>\n                                    </div>\n                                </div>\n                            </div><!-- /widget -->\n                        </div>\n\n                        <div class=\"span4\">\n                            <div id=\"load-average-widget\" class=\"widget\">\n                                <div class=\"widget-header\">\n                                    <i class=\"icon-laptop\"></i>\n                                    <h3>\n                                        Load average\n                                    </h3>\n                                    <div id=\"refresh-load\" class=\"btn icon-refresh js-refresh-info\"></div>\n                                </div><!-- /widget-header -->\n                                <div class=\"widget-content\">\n                                    <div style=\"text-align:center;\">\n                                        <b>Number of cores:</b> <span class=\"lead\" id=\"core-number\">0</span>\n                                    </div>\n                                    <div class=\"cf big_stats\">\n                                        <div class=\"stat\">\n                                            <i class=\"icon-#\">1 min&nbsp;</i> <span class=\"value odometer\" id=\"cpu-1min-per\"></span> %<br>\n                                            <span class=\"value\" id=\"cpu-1min\"></span>\n                                        </div><!-- .stat -->\n                                        <div class=\"stat\">\n                                            <i class=\"icon-#\">5 min&nbsp;</i> <span class=\"value odometer\" id=\"cpu-5min-per\"></span> %<br>\n                                            <span class=\"value\" id=\"cpu-5min\"></span>\n                                        </div><!-- .stat -->\n                                        <div class=\"stat\">\n                                            <i class=\"icon-#\">15 min&nbsp;</i> <span class=\"value odometer\" id=\"cpu-15min-per\"></span> %<br>\n                                            <span class=\"value\" id=\"cpu-15min\"></span>\n                                        </div><!-- .stat -->\n                                    </div>\n                                </div><!-- /widget-content -->\n                            </div><!-- /widget -->\n                        </div>\n\n                        <div class=\"span5\">\n                            <div id=\"ram-widget\" class=\"widget widget-nopad\">\n                                <div class=\"widget-header\">\n                                    <i class=\"icon-list-alt\"></i>\n                                    <h3>\n                                        RAM\n                                    </h3>\n                                    <div id=\"refresh-ram\" class=\"btn icon-refresh js-refresh-info\"></div>\n                                </div><!-- /widget-header -->\n                                <div class=\"widget-content\">\n                                    <div class=\"big-stats-container\">\n                                        <div class=\"widget-content\">\n                                            <div class=\"cf big_stats\">\n                                                <div class=\"stat\">\n                                                    <i class=\"icon-#\">Total&nbsp;</i> <span class=\"value odometer\" id=\"ram-total\"></span> MB\n                                                </div><!-- .stat -->\n                                                <div class=\"stat\">\n                                                    <i class=\"icon-#\">Used&nbsp;</i> <span class=\"value odometer\" id=\"ram-used\"></span> MB<br>\n                                                    <span class=\"value odometer\" id=\"ram-used-per\"></span> %\n                                                </div><!-- .stat -->\n                                                <div class=\"stat\">\n                                                    <i class=\"icon-#\">Free&nbsp;</i> <span class=\"value odometer\" id=\"ram-free\"></span> MB<br>\n                                                    <span class=\"value odometer\" id=\"ram-free-per\"></span> %\n                                                </div><!-- .stat -->\n                                            </div>\n                                        </div><!-- /widget-content -->\n                                    </div>\n                                </div>\n                            </div>\n                        </div>\n                      </div><!-- ./row -->\n\n                        <div class=\"row\">\t\t\t\n                            <div class=\"span12\">\n                                <div id=\"disk-usage-widget\" class=\"widget widget-table\">\n                                    <div class=\"widget-header\">\n                                        <i class=\"icon-list\"></i>\n                                        <h3>\n                                            Disk Usage\n                                        </h3>\n                                        <div id=\"refresh-df\" class=\"btn icon-refresh js-refresh-info\"></div>\n                                    </div><!-- /widget-header -->\n                                    <div class=\"widget-content\">\n                                        <table id=\"df_dashboard\" class=\"table table-hover table-condensed table-bordered\"></table>\n                                    </div><!-- /widget-content -->\n                                </div><!-- /widget -->\n                            </div>\n                        </div><!--./row -->\n\n                        <!-- diskstats -->\n                        <div class=\"row\">          \n                            <div class=\"span12\">\n                                <div id=\"diskstats-widget\" class=\"widget widget-table\">\n                                    <div class=\"widget-header\">\n                                        <i class=\"icon-exchange\"></i>\n                                        <h3>\n                                            Disk IO Stats\n                                        </h3>\n                                        <div id=\"refresh-diskstats\" class=\"btn icon-refresh js-refresh-info\"></div>\n                                    </div><!-- /widget-header -->\n                                    <div class=\"widget-content\">\n                                        <table id=\"diskstats_dashboard\" class=\"table table-hover table-condensed table-bordered\"></table>\n                                    </div><!-- /widget-content -->\n                                </div><!-- /widget -->\n                            </div>\n                        </div><!--./row -->\n\n                        <div class=\"row\">          \n                            <div class=\"span12\">\n                                <div id=\"cpu-widget\" class=\"widget widget-table\">\n                                    <div class=\"widget-header\">\n                                        <i class=\"icon-list\"></i>\n                                        <h3>\n                                            CPU\n                                        </h3>\n                                        <div id=\"refresh-cpu\" class=\"btn icon-refresh js-refresh-info\"></div>\n                                    </div><!-- /widget-header -->\n                                    <div class=\"widget-content\">\n                                        <table id=\"cpu_dashboard\" class=\"table table-hover table-condensed table-bordered\"></table>\n                                    </div><!-- /widget-content -->\n                                </div><!-- /widget -->\n                            </div>\n                        </div><!--./row -->\n\n                    </div><!-- #/widgets -->\n\n\n                    <div class=\"clear\"></div>\n                    <footer>\n                        <div class=\"site-source\">\n                            <a href=\"/\">Falcon-Agent</a> is open source on <a href=\"https://github.com/open-falcon/agent\" target=\"_blank\">GitHub</a>.<br />\n                            Patches, suggestions, and comments are welcome.\n                        </div>\n                        <div class=\"sfc-member\">\n                            Powered by <a href=\"http://ulricqin.com\">UlricQin</a>\n                        </div>\n                    </footer>\n\n\n                </div>\n            </div><!-- /main-inner -->\n        </div><!-- /main -->\n\n      \n\n        <!-- Javascript-->\n        <!-- Placed at the end of the document so the pages load faster -->\n        <script src=\"js/jquery.js\" type=\"text/javascript\"></script>\n        <script src=\"js/jquery-ui.min.js\" type=\"text/javascript\"></script>\n        <script src=\"js/bootstrap.js\" type=\"text/javascript\"></script>\n        <script src=\"js/jquery.dataTables.min.js\" type=\"text/javascript\"></script>\n        <script src=\"js/odometer.js\" type=\"text/javascript\"></script>\n        <script src=\"js/dashboard.js\" type=\"text/javascript\"></script>\n        <script src=\"js/base.js\" type=\"text/javascript\"></script>\n    </body>\n</html>\n\n"
  },
  {
    "path": "modules/agent/public/js/base.js",
    "content": "$(document).ready(function() {\n \n    // enable popovers\n    $(\".pop\").popover();\n\n   // activate tooltips on hover\n   $(\"[data-toggle='tooltip']\").tooltip({trigger: 'hover', placement:'right'});  \n\n    dashboard.getAll();\n}).on(\"click\", \".js-smoothscroll\", function(event) {\n    event.preventDefault();\n    var target = $(this.hash).parent();\n    pulseElement(target, 8, 400);\n\n    $(\"html,body\").animate({\n        scrollTop: target.offset().top - 130\n    }, 1000);\n}).on(\"click\", \".js-refresh-info\", function(event) {\n    event.preventDefault();\n    var target = event.target;\n    var item = target.id.split(\"-\").splice(-1)[0];\n\n    // if the refresh icon is click (where in a <span>) target will not have an id, so grab its parent instead\n    if(target.id == \"\") {\n        var parent = $(target).parent()[0];\n        item = parent.id.split(\"-\").splice(-1)[0];\n    }\n\n    dashboard.fnMap[item]();\n});\n\n// Handle for cancelling active effect.\nvar pulsing = {\n    element: null,\n    timeoutIDs: [],\n    resetfn: function() {\n        pulsing.element = null;\n        pulsing.timeoutIDs = [];\n    }\n};\n\n/**\n * Applies a pulse effect to the specified element. If triggered while already\n * active the ongoing effect is cancelled immediately.\n *\n * @param {HTMLElement} element The element to apply the effect to.\n * @param {Number} times How many pulses.\n * @param {Number} interval Milliseconds between pulses.\n */\nfunction pulseElement(element, times, interval) {\n    if (pulsing.element) {\n        pulsing.element.removeClass(\"pulse\").\n            parent().removeClass(\"pulse-border\");\n        pulsing.timeoutIDs.forEach(function(ID) {\n            clearTimeout(ID);\n        });\n        pulsing.timeoutIDs = [];\n    }\n    pulsing.element = element;\n    var parent = element.parent();\n    var f = function() {\n        element.toggleClass(\"pulse\");\n        parent.toggleClass(\"pulse-border\");\n    };\n\n    pulsing.timeoutIDs.push(setTimeout(pulsing.resetfn,\n                                       (times + 1) * interval));\n    for (; times > 0; --times) {\n        pulsing.timeoutIDs.push(setTimeout(f, times * interval));\n    }\n}\n\nfunction isInArray(array, search)\n{\n    return (array.indexOf(search) >= 0) ? true : false; \n}\n"
  },
  {
    "path": "modules/agent/public/js/bootstrap.js",
    "content": "/* ===================================================\n * bootstrap-transition.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#transitions\n * ===================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n!function( $ ) {\n\n  $(function () {\n\n    \"use strict\"\n\n    /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)\n     * ======================================================= */\n\n    $.support.transition = (function () {\n      var thisBody = document.body || document.documentElement\n        , thisStyle = thisBody.style\n        , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined\n\n      return support && {\n        end: (function () {\n          var transitionEnd = \"TransitionEnd\"\n          if ( $.browser.webkit ) {\n          \ttransitionEnd = \"webkitTransitionEnd\"\n          } else if ( $.browser.mozilla ) {\n          \ttransitionEnd = \"transitionend\"\n          } else if ( $.browser.opera ) {\n          \ttransitionEnd = \"oTransitionEnd\"\n          }\n          return transitionEnd\n        }())\n      }\n    })()\n\n  })\n\n}( window.jQuery );/* ==========================================================\n * bootstrap-alert.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#alerts\n * ==========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function( $ ){\n\n  \"use strict\"\n\n /* ALERT CLASS DEFINITION\n  * ====================== */\n\n  var dismiss = '[data-dismiss=\"alert\"]'\n    , Alert = function ( el ) {\n        $(el).on('click', dismiss, this.close)\n      }\n\n  Alert.prototype = {\n\n    constructor: Alert\n\n  , close: function ( e ) {\n      var $this = $(this)\n        , selector = $this.attr('data-target')\n        , $parent\n\n      if (!selector) {\n        selector = $this.attr('href')\n        selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') //strip for ie7\n      }\n\n      $parent = $(selector)\n      $parent.trigger('close')\n\n      e && e.preventDefault()\n\n      $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())\n\n      $parent\n        .trigger('close')\n        .removeClass('in')\n\n      function removeElement() {\n        $parent\n          .trigger('closed')\n          .remove()\n      }\n\n      $.support.transition && $parent.hasClass('fade') ?\n        $parent.on($.support.transition.end, removeElement) :\n        removeElement()\n    }\n\n  }\n\n\n /* ALERT PLUGIN DEFINITION\n  * ======================= */\n\n  $.fn.alert = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('alert')\n      if (!data) $this.data('alert', (data = new Alert(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  $.fn.alert.Constructor = Alert\n\n\n /* ALERT DATA-API\n  * ============== */\n\n  $(function () {\n    $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)\n  })\n\n}( window.jQuery );/* ============================================================\n * bootstrap-button.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#buttons\n * ============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n!function( $ ){\n\n  \"use strict\"\n\n /* BUTTON PUBLIC CLASS DEFINITION\n  * ============================== */\n\n  var Button = function ( element, options ) {\n    this.$element = $(element)\n    this.options = $.extend({}, $.fn.button.defaults, options)\n  }\n\n  Button.prototype = {\n\n      constructor: Button\n\n    , setState: function ( state ) {\n        var d = 'disabled'\n          , $el = this.$element\n          , data = $el.data()\n          , val = $el.is('input') ? 'val' : 'html'\n\n        state = state + 'Text'\n        data.resetText || $el.data('resetText', $el[val]())\n\n        $el[val](data[state] || this.options[state])\n\n        // push to event loop to allow forms to submit\n        setTimeout(function () {\n          state == 'loadingText' ?\n            $el.addClass(d).attr(d, d) :\n            $el.removeClass(d).removeAttr(d)\n        }, 0)\n      }\n\n    , toggle: function () {\n        var $parent = this.$element.parent('[data-toggle=\"buttons-radio\"]')\n\n        $parent && $parent\n          .find('.active')\n          .removeClass('active')\n\n        this.$element.toggleClass('active')\n      }\n\n  }\n\n\n /* BUTTON PLUGIN DEFINITION\n  * ======================== */\n\n  $.fn.button = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('button')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('button', (data = new Button(this, options)))\n      if (option == 'toggle') data.toggle()\n      else if (option) data.setState(option)\n    })\n  }\n\n  $.fn.button.defaults = {\n    loadingText: 'loading...'\n  }\n\n  $.fn.button.Constructor = Button\n\n\n /* BUTTON DATA-API\n  * =============== */\n\n  $(function () {\n    $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {\n      var $btn = $(e.target)\n      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')\n      $btn.button('toggle')\n    })\n  })\n\n}( window.jQuery );/* ==========================================================\n * bootstrap-carousel.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#carousel\n * ==========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function( $ ){\n\n  \"use strict\"\n\n /* CAROUSEL CLASS DEFINITION\n  * ========================= */\n\n  var Carousel = function (element, options) {\n    this.$element = $(element)\n    this.options = $.extend({}, $.fn.carousel.defaults, options)\n    this.options.slide && this.slide(this.options.slide)\n    this.options.pause == 'hover' && this.$element\n      .on('mouseenter', $.proxy(this.pause, this))\n      .on('mouseleave', $.proxy(this.cycle, this))\n  }\n\n  Carousel.prototype = {\n\n    cycle: function () {\n      this.interval = setInterval($.proxy(this.next, this), this.options.interval)\n      return this\n    }\n\n  , to: function (pos) {\n      var $active = this.$element.find('.active')\n        , children = $active.parent().children()\n        , activePos = children.index($active)\n        , that = this\n\n      if (pos > (children.length - 1) || pos < 0) return\n\n      if (this.sliding) {\n        return this.$element.one('slid', function () {\n          that.to(pos)\n        })\n      }\n\n      if (activePos == pos) {\n        return this.pause().cycle()\n      }\n\n      return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))\n    }\n\n  , pause: function () {\n      clearInterval(this.interval)\n      this.interval = null\n      return this\n    }\n\n  , next: function () {\n      if (this.sliding) return\n      return this.slide('next')\n    }\n\n  , prev: function () {\n      if (this.sliding) return\n      return this.slide('prev')\n    }\n\n  , slide: function (type, next) {\n      var $active = this.$element.find('.active')\n        , $next = next || $active[type]()\n        , isCycling = this.interval\n        , direction = type == 'next' ? 'left' : 'right'\n        , fallback  = type == 'next' ? 'first' : 'last'\n        , that = this\n\n      this.sliding = true\n\n      isCycling && this.pause()\n\n      $next = $next.length ? $next : this.$element.find('.item')[fallback]()\n\n      if ($next.hasClass('active')) return\n\n      if (!$.support.transition && this.$element.hasClass('slide')) {\n        this.$element.trigger('slide')\n        $active.removeClass('active')\n        $next.addClass('active')\n        this.sliding = false\n        this.$element.trigger('slid')\n      } else {\n        $next.addClass(type)\n        $next[0].offsetWidth // force reflow\n        $active.addClass(direction)\n        $next.addClass(direction)\n        this.$element.trigger('slide')\n        this.$element.one($.support.transition.end, function () {\n          $next.removeClass([type, direction].join(' ')).addClass('active')\n          $active.removeClass(['active', direction].join(' '))\n          that.sliding = false\n          setTimeout(function () { that.$element.trigger('slid') }, 0)\n        })\n      }\n\n      isCycling && this.cycle()\n\n      return this\n    }\n\n  }\n\n\n /* CAROUSEL PLUGIN DEFINITION\n  * ========================== */\n\n  $.fn.carousel = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('carousel')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('carousel', (data = new Carousel(this, options)))\n      if (typeof option == 'number') data.to(option)\n      else if (typeof option == 'string' || (option = options.slide)) data[option]()\n      else data.cycle()\n    })\n  }\n\n  $.fn.carousel.defaults = {\n    interval: 5000\n  , pause: 'hover'\n  }\n\n  $.fn.carousel.Constructor = Carousel\n\n\n /* CAROUSEL DATA-API\n  * ================= */\n\n  $(function () {\n    $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {\n      var $this = $(this), href\n        , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) //strip for ie7\n        , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())\n      $target.carousel(options)\n      e.preventDefault()\n    })\n  })\n\n}( window.jQuery );/* =============================================================\n * bootstrap-collapse.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#collapse\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n!function( $ ){\n\n  \"use strict\"\n\n  var Collapse = function ( element, options ) {\n  \tthis.$element = $(element)\n    this.options = $.extend({}, $.fn.collapse.defaults, options)\n\n    if (this.options[\"parent\"]) {\n      this.$parent = $(this.options[\"parent\"])\n    }\n\n    this.options.toggle && this.toggle()\n  }\n\n  Collapse.prototype = {\n\n    constructor: Collapse\n\n  , dimension: function () {\n      var hasWidth = this.$element.hasClass('width')\n      return hasWidth ? 'width' : 'height'\n    }\n\n  , show: function () {\n      var dimension = this.dimension()\n        , scroll = $.camelCase(['scroll', dimension].join('-'))\n        , actives = this.$parent && this.$parent.find('.in')\n        , hasData\n\n      if (actives && actives.length) {\n        hasData = actives.data('collapse')\n        actives.collapse('hide')\n        hasData || actives.data('collapse', null)\n      }\n\n      this.$element[dimension](0)\n      this.transition('addClass', 'show', 'shown')\n      this.$element[dimension](this.$element[0][scroll])\n\n    }\n\n  , hide: function () {\n      var dimension = this.dimension()\n      this.reset(this.$element[dimension]())\n      this.transition('removeClass', 'hide', 'hidden')\n      this.$element[dimension](0)\n    }\n\n  , reset: function ( size ) {\n      var dimension = this.dimension()\n\n      this.$element\n        .removeClass('collapse')\n        [dimension](size || 'auto')\n        [0].offsetWidth\n\n      this.$element[size ? 'addClass' : 'removeClass']('collapse')\n\n      return this\n    }\n\n  , transition: function ( method, startEvent, completeEvent ) {\n      var that = this\n        , complete = function () {\n            if (startEvent == 'show') that.reset()\n            that.$element.trigger(completeEvent)\n          }\n\n      this.$element\n        .trigger(startEvent)\n        [method]('in')\n\n      $.support.transition && this.$element.hasClass('collapse') ?\n        this.$element.one($.support.transition.end, complete) :\n        complete()\n  \t}\n\n  , toggle: function () {\n      this[this.$element.hasClass('in') ? 'hide' : 'show']()\n  \t}\n\n  }\n\n  /* COLLAPSIBLE PLUGIN DEFINITION\n  * ============================== */\n\n  $.fn.collapse = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('collapse')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('collapse', (data = new Collapse(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.collapse.defaults = {\n    toggle: true\n  }\n\n  $.fn.collapse.Constructor = Collapse\n\n\n /* COLLAPSIBLE DATA-API\n  * ==================== */\n\n  $(function () {\n    $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {\n      var $this = $(this), href\n        , target = $this.attr('data-target')\n          || e.preventDefault()\n          || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') //strip for ie7\n        , option = $(target).data('collapse') ? 'toggle' : $this.data()\n      $(target).collapse(option)\n    })\n  })\n\n}( window.jQuery );/* ============================================================\n * bootstrap-dropdown.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#dropdowns\n * ============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function( $ ){\n\n  \"use strict\"\n\n /* DROPDOWN CLASS DEFINITION\n  * ========================= */\n\n  var toggle = '[data-toggle=\"dropdown\"]'\n    , Dropdown = function ( element ) {\n        var $el = $(element).on('click.dropdown.data-api', this.toggle)\n        $('html').on('click.dropdown.data-api', function () {\n          $el.parent().removeClass('open')\n        })\n      }\n\n  Dropdown.prototype = {\n\n    constructor: Dropdown\n\n  , toggle: function ( e ) {\n      var $this = $(this)\n        , selector = $this.attr('data-target')\n        , $parent\n        , isActive\n\n      if (!selector) {\n        selector = $this.attr('href')\n        selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') //strip for ie7\n      }\n\n      $parent = $(selector)\n      $parent.length || ($parent = $this.parent())\n\n      isActive = $parent.hasClass('open')\n\n      clearMenus()\n      !isActive && $parent.toggleClass('open')\n\n      return false\n    }\n\n  }\n\n  function clearMenus() {\n    $(toggle).parent().removeClass('open')\n  }\n\n\n  /* DROPDOWN PLUGIN DEFINITION\n   * ========================== */\n\n  $.fn.dropdown = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('dropdown')\n      if (!data) $this.data('dropdown', (data = new Dropdown(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  $.fn.dropdown.Constructor = Dropdown\n\n\n  /* APPLY TO STANDARD DROPDOWN ELEMENTS\n   * =================================== */\n\n  $(function () {\n    $('html').on('click.dropdown.data-api', clearMenus)\n    $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)\n  })\n\n}( window.jQuery );/* =========================================================\n * bootstrap-modal.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#modals\n * =========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================= */\n\n\n!function( $ ){\n\n  \"use strict\"\n\n /* MODAL CLASS DEFINITION\n  * ====================== */\n\n  var Modal = function ( content, options ) {\n    this.options = options\n    this.$element = $(content)\n      .delegate('[data-dismiss=\"modal\"]', 'click.dismiss.modal', $.proxy(this.hide, this))\n  }\n\n  Modal.prototype = {\n\n      constructor: Modal\n\n    , toggle: function () {\n        return this[!this.isShown ? 'show' : 'hide']()\n      }\n\n    , show: function () {\n        var that = this\n\n        if (this.isShown) return\n\n        $('body').addClass('modal-open')\n\n        this.isShown = true\n        this.$element.trigger('show')\n\n        escape.call(this)\n        backdrop.call(this, function () {\n          var transition = $.support.transition && that.$element.hasClass('fade')\n\n          !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position\n\n          that.$element\n            .show()\n\n          if (transition) {\n            that.$element[0].offsetWidth // force reflow\n          }\n\n          that.$element.addClass('in')\n\n          transition ?\n            that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :\n            that.$element.trigger('shown')\n\n        })\n      }\n\n    , hide: function ( e ) {\n        e && e.preventDefault()\n\n        if (!this.isShown) return\n\n        var that = this\n        this.isShown = false\n\n        $('body').removeClass('modal-open')\n\n        escape.call(this)\n\n        this.$element\n          .trigger('hide')\n          .removeClass('in')\n\n        $.support.transition && this.$element.hasClass('fade') ?\n          hideWithTransition.call(this) :\n          hideModal.call(this)\n      }\n\n  }\n\n\n /* MODAL PRIVATE METHODS\n  * ===================== */\n\n  function hideWithTransition() {\n    var that = this\n      , timeout = setTimeout(function () {\n          that.$element.off($.support.transition.end)\n          hideModal.call(that)\n        }, 500)\n\n    this.$element.one($.support.transition.end, function () {\n      clearTimeout(timeout)\n      hideModal.call(that)\n    })\n  }\n\n  function hideModal( that ) {\n    this.$element\n      .hide()\n      .trigger('hidden')\n\n    backdrop.call(this)\n  }\n\n  function backdrop( callback ) {\n    var that = this\n      , animate = this.$element.hasClass('fade') ? 'fade' : ''\n\n    if (this.isShown && this.options.backdrop) {\n      var doAnimate = $.support.transition && animate\n\n      this.$backdrop = $('<div class=\"modal-backdrop ' + animate + '\" />')\n        .appendTo(document.body)\n\n      if (this.options.backdrop != 'static') {\n        this.$backdrop.click($.proxy(this.hide, this))\n      }\n\n      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n\n      this.$backdrop.addClass('in')\n\n      doAnimate ?\n        this.$backdrop.one($.support.transition.end, callback) :\n        callback()\n\n    } else if (!this.isShown && this.$backdrop) {\n      this.$backdrop.removeClass('in')\n\n      $.support.transition && this.$element.hasClass('fade')?\n        this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :\n        removeBackdrop.call(this)\n\n    } else if (callback) {\n      callback()\n    }\n  }\n\n  function removeBackdrop() {\n    this.$backdrop.remove()\n    this.$backdrop = null\n  }\n\n  function escape() {\n    var that = this\n    if (this.isShown && this.options.keyboard) {\n      $(document).on('keyup.dismiss.modal', function ( e ) {\n        e.which == 27 && that.hide()\n      })\n    } else if (!this.isShown) {\n      $(document).off('keyup.dismiss.modal')\n    }\n  }\n\n\n /* MODAL PLUGIN DEFINITION\n  * ======================= */\n\n  $.fn.modal = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('modal')\n        , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)\n      if (!data) $this.data('modal', (data = new Modal(this, options)))\n      if (typeof option == 'string') data[option]()\n      else if (options.show) data.show()\n    })\n  }\n\n  $.fn.modal.defaults = {\n      backdrop: true\n    , keyboard: true\n    , show: true\n  }\n\n  $.fn.modal.Constructor = Modal\n\n\n /* MODAL DATA-API\n  * ============== */\n\n  $(function () {\n    $('body').on('click.modal.data-api', '[data-toggle=\"modal\"]', function ( e ) {\n      var $this = $(this), href\n        , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) //strip for ie7\n        , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())\n\n      e.preventDefault()\n      $target.modal(option)\n    })\n  })\n\n}( window.jQuery );/* ===========================================================\n * bootstrap-tooltip.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#tooltips\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ===========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n!function( $ ) {\n\n  \"use strict\"\n\n /* TOOLTIP PUBLIC CLASS DEFINITION\n  * =============================== */\n\n  var Tooltip = function ( element, options ) {\n    this.init('tooltip', element, options)\n  }\n\n  Tooltip.prototype = {\n\n    constructor: Tooltip\n\n  , init: function ( type, element, options ) {\n      var eventIn\n        , eventOut\n\n      this.type = type\n      this.$element = $(element)\n      this.options = this.getOptions(options)\n      this.enabled = true\n\n      if (this.options.trigger != 'manual') {\n        eventIn  = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'\n        eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'\n        this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))\n        this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))\n      }\n\n      this.options.selector ?\n        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n        this.fixTitle()\n    }\n\n  , getOptions: function ( options ) {\n      options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())\n\n      if (options.delay && typeof options.delay == 'number') {\n        options.delay = {\n          show: options.delay\n        , hide: options.delay\n        }\n      }\n\n      return options\n    }\n\n  , enter: function ( e ) {\n      var self = $(e.currentTarget)[this.type](this._options).data(this.type)\n\n      if (!self.options.delay || !self.options.delay.show) {\n        self.show()\n      } else {\n        self.hoverState = 'in'\n        setTimeout(function() {\n          if (self.hoverState == 'in') {\n            self.show()\n          }\n        }, self.options.delay.show)\n      }\n    }\n\n  , leave: function ( e ) {\n      var self = $(e.currentTarget)[this.type](this._options).data(this.type)\n\n      if (!self.options.delay || !self.options.delay.hide) {\n        self.hide()\n      } else {\n        self.hoverState = 'out'\n        setTimeout(function() {\n          if (self.hoverState == 'out') {\n            self.hide()\n          }\n        }, self.options.delay.hide)\n      }\n    }\n\n  , show: function () {\n      var $tip\n        , inside\n        , pos\n        , actualWidth\n        , actualHeight\n        , placement\n        , tp\n\n      if (this.hasContent() && this.enabled) {\n        $tip = this.tip()\n        this.setContent()\n\n        if (this.options.animation) {\n          $tip.addClass('fade')\n        }\n\n        placement = typeof this.options.placement == 'function' ?\n          this.options.placement.call(this, $tip[0], this.$element[0]) :\n          this.options.placement\n\n        inside = /in/.test(placement)\n\n        $tip\n          .remove()\n          .css({ top: 0, left: 0, display: 'block' })\n          .appendTo(inside ? this.$element : document.body)\n\n        pos = this.getPosition(inside)\n\n        actualWidth = $tip[0].offsetWidth\n        actualHeight = $tip[0].offsetHeight\n\n        switch (inside ? placement.split(' ')[1] : placement) {\n          case 'bottom':\n            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}\n            break\n          case 'top':\n            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}\n            break\n          case 'left':\n            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}\n            break\n          case 'right':\n            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}\n            break\n        }\n\n        $tip\n          .css(tp)\n          .addClass(placement)\n          .addClass('in')\n      }\n    }\n\n  , setContent: function () {\n      var $tip = this.tip()\n      $tip.find('.tooltip-inner').html(this.getTitle())\n      $tip.removeClass('fade in top bottom left right')\n    }\n\n  , hide: function () {\n      var that = this\n        , $tip = this.tip()\n\n      $tip.removeClass('in')\n\n      function removeWithAnimation() {\n        var timeout = setTimeout(function () {\n          $tip.off($.support.transition.end).remove()\n        }, 500)\n\n        $tip.one($.support.transition.end, function () {\n          clearTimeout(timeout)\n          $tip.remove()\n        })\n      }\n\n      $.support.transition && this.$tip.hasClass('fade') ?\n        removeWithAnimation() :\n        $tip.remove()\n    }\n\n  , fixTitle: function () {\n      var $e = this.$element\n      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {\n        $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')\n      }\n    }\n\n  , hasContent: function () {\n      return this.getTitle()\n    }\n\n  , getPosition: function (inside) {\n      return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {\n        width: this.$element[0].offsetWidth\n      , height: this.$element[0].offsetHeight\n      })\n    }\n\n  , getTitle: function () {\n      var title\n        , $e = this.$element\n        , o = this.options\n\n      title = $e.attr('data-original-title')\n        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)\n\n      title = (title || '').toString().replace(/(^\\s*|\\s*$)/, \"\")\n\n      return title\n    }\n\n  , tip: function () {\n      return this.$tip = this.$tip || $(this.options.template)\n    }\n\n  , validate: function () {\n      if (!this.$element[0].parentNode) {\n        this.hide()\n        this.$element = null\n        this.options = null\n      }\n    }\n\n  , enable: function () {\n      this.enabled = true\n    }\n\n  , disable: function () {\n      this.enabled = false\n    }\n\n  , toggleEnabled: function () {\n      this.enabled = !this.enabled\n    }\n\n  , toggle: function () {\n      this[this.tip().hasClass('in') ? 'hide' : 'show']()\n    }\n\n  }\n\n\n /* TOOLTIP PLUGIN DEFINITION\n  * ========================= */\n\n  $.fn.tooltip = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('tooltip')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.tooltip.Constructor = Tooltip\n\n  $.fn.tooltip.defaults = {\n    animation: true\n  , delay: 0\n  , selector: false\n  , placement: 'top'\n  , trigger: 'hover'\n  , title: ''\n  , template: '<div class=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>'\n  }\n\n}( window.jQuery );/* ===========================================================\n * bootstrap-popover.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#popovers\n * ===========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * =========================================================== */\n\n\n!function( $ ) {\n\n \"use strict\"\n\n  var Popover = function ( element, options ) {\n    this.init('popover', element, options)\n  }\n\n  /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js\n     ========================================== */\n\n  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {\n\n    constructor: Popover\n\n  , setContent: function () {\n      var $tip = this.tip()\n        , title = this.getTitle()\n        , content = this.getContent()\n\n      $tip.find('.popover-title')[ $.type(title) == 'object' ? 'append' : 'html' ](title)\n      $tip.find('.popover-content > *')[ $.type(content) == 'object' ? 'append' : 'html' ](content)\n\n      $tip.removeClass('fade top bottom left right in')\n    }\n\n  , hasContent: function () {\n      return this.getTitle() || this.getContent()\n    }\n\n  , getContent: function () {\n      var content\n        , $e = this.$element\n        , o = this.options\n\n      content = $e.attr('data-content')\n        || (typeof o.content == 'function' ? o.content.call($e[0]) :  o.content)\n\n      content = content.toString().replace(/(^\\s*|\\s*$)/, \"\")\n\n      return content\n    }\n\n  , tip: function() {\n      if (!this.$tip) {\n        this.$tip = $(this.options.template)\n      }\n      return this.$tip\n    }\n\n  })\n\n\n /* POPOVER PLUGIN DEFINITION\n  * ======================= */\n\n  $.fn.popover = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('popover')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('popover', (data = new Popover(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.popover.Constructor = Popover\n\n  $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {\n    placement: 'right'\n  , content: ''\n  , template: '<div class=\"popover\"><div class=\"arrow\"></div><div class=\"popover-inner\"><h3 class=\"popover-title\"></h3><div class=\"popover-content\"><p></p></div></div></div>'\n  })\n\n}( window.jQuery );/* =============================================================\n * bootstrap-scrollspy.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#scrollspy\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================== */\n\n!function ( $ ) {\n\n  \"use strict\"\n\n  /* SCROLLSPY CLASS DEFINITION\n   * ========================== */\n\n  function ScrollSpy( element, options) {\n    var process = $.proxy(this.process, this)\n      , $element = $(element).is('body') ? $(window) : $(element)\n      , href\n    this.options = $.extend({}, $.fn.scrollspy.defaults, options)\n    this.$scrollElement = $element.on('scroll.scroll.data-api', process)\n    this.selector = (this.options.target\n      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) //strip for ie7\n      || '') + ' .nav li > a'\n    this.$body = $('body').on('click.scroll.data-api', this.selector, process)\n    this.refresh()\n    this.process()\n  }\n\n  ScrollSpy.prototype = {\n\n      constructor: ScrollSpy\n\n    , refresh: function () {\n        this.targets = this.$body\n          .find(this.selector)\n          .map(function () {\n            var href = $(this).attr('href')\n            return /^#\\w/.test(href) && $(href).length ? href : null\n          })\n\n        this.offsets = $.map(this.targets, function (id) {\n          return $(id).position().top\n        })\n      }\n\n    , process: function () {\n        var scrollTop = this.$scrollElement.scrollTop() + this.options.offset\n          , offsets = this.offsets\n          , targets = this.targets\n          , activeTarget = this.activeTarget\n          , i\n\n        for (i = offsets.length; i--;) {\n          activeTarget != targets[i]\n            && scrollTop >= offsets[i]\n            && (!offsets[i + 1] || scrollTop <= offsets[i + 1])\n            && this.activate( targets[i] )\n        }\n      }\n\n    , activate: function (target) {\n        var active\n\n        this.activeTarget = target\n\n        this.$body\n          .find(this.selector).parent('.active')\n          .removeClass('active')\n\n        active = this.$body\n          .find(this.selector + '[href=\"' + target + '\"]')\n          .parent('li')\n          .addClass('active')\n\n        if ( active.parent('.dropdown-menu') )  {\n          active.closest('li.dropdown').addClass('active')\n        }\n      }\n\n  }\n\n\n /* SCROLLSPY PLUGIN DEFINITION\n  * =========================== */\n\n  $.fn.scrollspy = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('scrollspy')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.scrollspy.Constructor = ScrollSpy\n\n  $.fn.scrollspy.defaults = {\n    offset: 10\n  }\n\n\n /* SCROLLSPY DATA-API\n  * ================== */\n\n  $(function () {\n    $('[data-spy=\"scroll\"]').each(function () {\n      var $spy = $(this)\n      $spy.scrollspy($spy.data())\n    })\n  })\n\n}( window.jQuery );/* ========================================================\n * bootstrap-tab.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#tabs\n * ========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ======================================================== */\n\n\n!function( $ ){\n\n  \"use strict\"\n\n /* TAB CLASS DEFINITION\n  * ==================== */\n\n  var Tab = function ( element ) {\n    this.element = $(element)\n  }\n\n  Tab.prototype = {\n\n    constructor: Tab\n\n  , show: function () {\n      var $this = this.element\n        , $ul = $this.closest('ul:not(.dropdown-menu)')\n        , selector = $this.attr('data-target')\n        , previous\n        , $target\n\n      if (!selector) {\n        selector = $this.attr('href')\n        selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') //strip for ie7\n      }\n\n      if ( $this.parent('li').hasClass('active') ) return\n\n      previous = $ul.find('.active a').last()[0]\n\n      $this.trigger({\n        type: 'show'\n      , relatedTarget: previous\n      })\n\n      $target = $(selector)\n\n      this.activate($this.parent('li'), $ul)\n      this.activate($target, $target.parent(), function () {\n        $this.trigger({\n          type: 'shown'\n        , relatedTarget: previous\n        })\n      })\n    }\n\n  , activate: function ( element, container, callback) {\n      var $active = container.find('> .active')\n        , transition = callback\n            && $.support.transition\n            && $active.hasClass('fade')\n\n      function next() {\n        $active\n          .removeClass('active')\n          .find('> .dropdown-menu > .active')\n          .removeClass('active')\n\n        element.addClass('active')\n\n        if (transition) {\n          element[0].offsetWidth // reflow for transition\n          element.addClass('in')\n        } else {\n          element.removeClass('fade')\n        }\n\n        if ( element.parent('.dropdown-menu') ) {\n          element.closest('li.dropdown').addClass('active')\n        }\n\n        callback && callback()\n      }\n\n      transition ?\n        $active.one($.support.transition.end, next) :\n        next()\n\n      $active.removeClass('in')\n    }\n  }\n\n\n /* TAB PLUGIN DEFINITION\n  * ===================== */\n\n  $.fn.tab = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('tab')\n      if (!data) $this.data('tab', (data = new Tab(this)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.tab.Constructor = Tab\n\n\n /* TAB DATA-API\n  * ============ */\n\n  $(function () {\n    $('body').on('click.tab.data-api', '[data-toggle=\"tab\"], [data-toggle=\"pill\"]', function (e) {\n      e.preventDefault()\n      $(this).tab('show')\n    })\n  })\n\n}( window.jQuery );/* =============================================================\n * bootstrap-typeahead.js v2.0.2\n * http://twitter.github.com/bootstrap/javascript.html#typeahead\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n!function( $ ){\n\n  \"use strict\"\n\n  var Typeahead = function ( element, options ) {\n    this.$element = $(element)\n    this.options = $.extend({}, $.fn.typeahead.defaults, options)\n    this.matcher = this.options.matcher || this.matcher\n    this.sorter = this.options.sorter || this.sorter\n    this.highlighter = this.options.highlighter || this.highlighter\n    this.$menu = $(this.options.menu).appendTo('body')\n    this.source = this.options.source\n    this.shown = false\n    this.listen()\n  }\n\n  Typeahead.prototype = {\n\n    constructor: Typeahead\n\n  , select: function () {\n      var val = this.$menu.find('.active').attr('data-value')\n      this.$element.val(val)\n      this.$element.change();\n      return this.hide()\n    }\n\n  , show: function () {\n      var pos = $.extend({}, this.$element.offset(), {\n        height: this.$element[0].offsetHeight\n      })\n\n      this.$menu.css({\n        top: pos.top + pos.height\n      , left: pos.left\n      })\n\n      this.$menu.show()\n      this.shown = true\n      return this\n    }\n\n  , hide: function () {\n      this.$menu.hide()\n      this.shown = false\n      return this\n    }\n\n  , lookup: function (event) {\n      var that = this\n        , items\n        , q\n\n      this.query = this.$element.val()\n\n      if (!this.query) {\n        return this.shown ? this.hide() : this\n      }\n\n      items = $.grep(this.source, function (item) {\n        if (that.matcher(item)) return item\n      })\n\n      items = this.sorter(items)\n\n      if (!items.length) {\n        return this.shown ? this.hide() : this\n      }\n\n      return this.render(items.slice(0, this.options.items)).show()\n    }\n\n  , matcher: function (item) {\n      return ~item.toLowerCase().indexOf(this.query.toLowerCase())\n    }\n\n  , sorter: function (items) {\n      var beginswith = []\n        , caseSensitive = []\n        , caseInsensitive = []\n        , item\n\n      while (item = items.shift()) {\n        if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)\n        else if (~item.indexOf(this.query)) caseSensitive.push(item)\n        else caseInsensitive.push(item)\n      }\n\n      return beginswith.concat(caseSensitive, caseInsensitive)\n    }\n\n  , highlighter: function (item) {\n      return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) {\n        return '<strong>' + match + '</strong>'\n      })\n    }\n\n  , render: function (items) {\n      var that = this\n\n      items = $(items).map(function (i, item) {\n        i = $(that.options.item).attr('data-value', item)\n        i.find('a').html(that.highlighter(item))\n        return i[0]\n      })\n\n      items.first().addClass('active')\n      this.$menu.html(items)\n      return this\n    }\n\n  , next: function (event) {\n      var active = this.$menu.find('.active').removeClass('active')\n        , next = active.next()\n\n      if (!next.length) {\n        next = $(this.$menu.find('li')[0])\n      }\n\n      next.addClass('active')\n    }\n\n  , prev: function (event) {\n      var active = this.$menu.find('.active').removeClass('active')\n        , prev = active.prev()\n\n      if (!prev.length) {\n        prev = this.$menu.find('li').last()\n      }\n\n      prev.addClass('active')\n    }\n\n  , listen: function () {\n      this.$element\n        .on('blur',     $.proxy(this.blur, this))\n        .on('keypress', $.proxy(this.keypress, this))\n        .on('keyup',    $.proxy(this.keyup, this))\n\n      if ($.browser.webkit || $.browser.msie) {\n        this.$element.on('keydown', $.proxy(this.keypress, this))\n      }\n\n      this.$menu\n        .on('click', $.proxy(this.click, this))\n        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))\n    }\n\n  , keyup: function (e) {\n      switch(e.keyCode) {\n        case 40: // down arrow\n        case 38: // up arrow\n          break\n\n        case 9: // tab\n        case 13: // enter\n          if (!this.shown) return\n          this.select()\n          break\n\n        case 27: // escape\n          if (!this.shown) return\n          this.hide()\n          break\n\n        default:\n          this.lookup()\n      }\n\n      e.stopPropagation()\n      e.preventDefault()\n  }\n\n  , keypress: function (e) {\n      if (!this.shown) return\n\n      switch(e.keyCode) {\n        case 9: // tab\n        case 13: // enter\n        case 27: // escape\n          e.preventDefault()\n          break\n\n        case 38: // up arrow\n          e.preventDefault()\n          this.prev()\n          break\n\n        case 40: // down arrow\n          e.preventDefault()\n          this.next()\n          break\n      }\n\n      e.stopPropagation()\n    }\n\n  , blur: function (e) {\n      var that = this\n      setTimeout(function () { that.hide() }, 150)\n    }\n\n  , click: function (e) {\n      e.stopPropagation()\n      e.preventDefault()\n      this.select()\n    }\n\n  , mouseenter: function (e) {\n      this.$menu.find('.active').removeClass('active')\n      $(e.currentTarget).addClass('active')\n    }\n\n  }\n\n\n  /* TYPEAHEAD PLUGIN DEFINITION\n   * =========================== */\n\n  $.fn.typeahead = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('typeahead')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.typeahead.defaults = {\n    source: []\n  , items: 8\n  , menu: '<ul class=\"typeahead dropdown-menu\"></ul>'\n  , item: '<li><a href=\"#\"></a></li>'\n  }\n\n  $.fn.typeahead.Constructor = Typeahead\n\n\n /* TYPEAHEAD DATA-API\n  * ================== */\n\n  $(function () {\n    $('body').on('focus.typeahead.data-api', '[data-provide=\"typeahead\"]', function (e) {\n      var $this = $(this)\n      if ($this.data('typeahead')) return\n      e.preventDefault()\n      $this.typeahead($this.data())\n    })\n  })\n\n}( window.jQuery );"
  },
  {
    "path": "modules/agent/public/js/dashboard.js",
    "content": "// Gets data from provided url and updates DOM element.\nfunction generate_os_data(url, element) {\n    $.get(url, function (d) {\n        if (d.msg == \"success\") {\n            $(element).text(d.data);\n        } else {\n            $(element).text(d.msg);\n        }\n    }, \"json\");\n}\n\n// If dataTable with provided ID exists, destroy it.\nfunction destroy_dataTable(table_id) {\n    var table = $(\"#\" + table_id);\n    var ex = document.getElementById(table_id);\n    if ($.fn.DataTable.fnIsDataTable(ex)) {\n        table.hide().dataTable().fnClearTable();\n        table.dataTable().fnDestroy();\n    }\n}\n\n//DataTables\n//Sort file size data.\njQuery.extend(jQuery.fn.dataTableExt.oSort, {\n    \"file-size-units\": {\n        K: 1024,\n        M: Math.pow(1024, 2),\n        G: Math.pow(1024, 3),\n        T: Math.pow(1024, 4),\n        P: Math.pow(1024, 5),\n        E: Math.pow(1024, 6)\n    },\n\n    \"file-size-pre\": function (a) {\n        var x = a.substring(0, a.length - 1);\n        var x_unit = a.substring(a.length - 1, a.length);\n        if (jQuery.fn.dataTableExt.oSort['file-size-units'][x_unit]) {\n            return parseInt(x * jQuery.fn.dataTableExt.oSort['file-size-units'][x_unit], 10);\n        }\n        else {\n            return parseInt(x + x_unit, 10);\n        }\n    },\n\n    \"file-size-asc\": function (a, b) {\n        return ((a < b) ? -1 : ((a > b) ? 1 : 0));\n    },\n\n    \"file-size-desc\": function (a, b) {\n        return ((a < b) ? 1 : ((a > b) ? -1 : 0));\n    }\n});\n\n//DataTables\n//Sort numeric data which has a percent sign with it.\njQuery.extend(jQuery.fn.dataTableExt.oSort, {\n    \"percent-pre\": function (a) {\n        var x = (a === \"-\") ? 0 : a.replace(/%/, \"\");\n        return parseFloat(x);\n    },\n\n    \"percent-asc\": function (a, b) {\n        return ((a < b) ? -1 : ((a > b) ? 1 : 0));\n    },\n\n    \"percent-desc\": function (a, b) {\n        return ((a < b) ? 1 : ((a > b) ? -1 : 0));\n    }\n});\n\n//DataTables\n//Sort IP addresses\njQuery.extend(jQuery.fn.dataTableExt.oSort, {\n    \"ip-address-pre\": function (a) {\n        // split the address into octets\n        //\n        var x = a.split('.');\n\n        // pad each of the octets to three digits in length\n        //\n        function zeroPad(num, places) {\n            var zero = places - num.toString().length + 1;\n            return Array(+(zero > 0 && zero)).join(\"0\") + num;\n        }\n\n        // build the resulting IP\n        var r = '';\n        for (var i = 0; i < x.length; i++)\n            r = r + zeroPad(x[i], 3);\n\n        // return the formatted IP address\n        //\n        return r;\n    },\n\n    \"ip-address-asc\": function (a, b) {\n        return ((a < b) ? -1 : ((a > b) ? 1 : 0));\n    },\n\n    \"ip-address-desc\": function (a, b) {\n        return ((a < b) ? 1 : ((a > b) ? -1 : 0));\n    }\n});\n\n/*******************************\n Data Call Functions\n *******************************/\n\nvar dashboard = {};\n\ndashboard.getRam = function () {\n    $.get(\"page/memory\", function (data) {\n        if (data.msg == \"success\") {\n            var ram_total = data.data[0];\n            var ram_used = Math.round((data.data[1] / ram_total) * 100);\n            var ram_free = Math.round((data.data[2] / ram_total) * 100);\n\n            $(\"#ram-total\").text(ram_total);\n            $(\"#ram-used\").text(data.data[1]);\n            $(\"#ram-free\").text(data.data[2]);\n\n            $(\"#ram-free-per\").text(ram_free);\n            $(\"#ram-used-per\").text(ram_used);\n        }\n    }, \"json\");\n}\n\ndashboard.getDf = function () {\n    $.get(\"page/df\", function (data) {\n        var table = $(\"#df_dashboard\");\n        var ex = document.getElementById(\"df_dashboard\");\n        if ($.fn.DataTable.fnIsDataTable(ex)) {\n            table.hide().dataTable().fnClearTable();\n            table.dataTable().fnDestroy();\n        }\n\n        table.dataTable({\n            aaData: data.data,\n            aoColumns: [\n                { sTitle: \"Filesystem\" },\n                { sTitle: \"BTotal\", sType: \"file-size\" },\n                { sTitle: \"BUsed\", sType: \"file-size\" },\n                { sTitle: \"BFree\", sType: \"file-size\" },\n                { sTitle: \"BUse%\", sType: \"percent\" },\n                { sTitle: \"Mounted\" },\n                { sTitle: \"ITotal\", sType: \"file-size\" },\n                { sTitle: \"IUsed\", sType: \"file-size\" },\n                { sTitle: \"IFree\", sType: \"file-size\" },\n                { sTitle: \"IUse%\", sType: \"percent\" },\n                { sTitle: \"Vfstype\" }\n            ],\n            bPaginate: false,\n            bFilter: false,\n            bAutoWidth: true,\n            bInfo: false\n        }).fadeIn();\n    }, \"json\");\n}\n\ndashboard.getCpu = function () {\n    $.get(\"page/cpu/usage\", function (data) {\n        if (data.msg != \"success\") {\n            return\n        }\n        \n        var table = $(\"#cpu_dashboard\");\n        var ex = document.getElementById(\"cpu_dashboard\");\n        if ($.fn.DataTable.fnIsDataTable(ex)) {\n            table.hide().dataTable().fnClearTable();\n            table.dataTable().fnDestroy();\n        }\n\n        table.dataTable({\n            aaData: data.data,\n            aoColumns: [\n                { sTitle: \"idle\"},\n                { sTitle: \"busy\"},\n                { sTitle: \"user\"},\n                { sTitle: \"nice\"},\n                { sTitle: \"system\"},\n                { sTitle: \"iowait\"},\n                { sTitle: \"irq\"},\n                { sTitle: \"softirq\"},\n                { sTitle: \"steal\"},\n                { sTitle: \"guest\"}\n            ],\n            bPaginate: false,\n            bFilter: false,\n            bAutoWidth: true,\n            bInfo: false\n        }).fadeIn();\n    }, \"json\");\n}\n\ndashboard.getDiskstats = function () {\n    $.get(\"page/diskio\", function (data) {\n        var table = $(\"#diskstats_dashboard\");\n        var ex = document.getElementById(\"diskstats_dashboard\");\n        if ($.fn.DataTable.fnIsDataTable(ex)) {\n            table.hide().dataTable().fnClearTable();\n            table.dataTable().fnDestroy();\n        }\n\n        table.dataTable({\n            aaData: data.data,\n            aoColumns: [\n                { sTitle: \"Device\"},\n                { sTitle: \"rrqm/s\"},\n                { sTitle: \"wrqm/s\"},\n                { sTitle: \"r/s\"},\n                { sTitle: \"w/s\"},\n                { sTitle: \"rkB/s\"},\n                { sTitle: \"wkB/s\"},\n                { sTitle: \"avgrq-sz\"},\n                { sTitle: \"avgqu-sz\"},\n                { sTitle: \"await\"},\n                { sTitle: \"svctm\"},\n                { sTitle: \"%util\"},\n            ],\n            bPaginate: false,\n            bFilter: false,\n            bAutoWidth: true,\n            bInfo: false\n        }).fadeIn();\n    }, \"json\");\n}\n\ndashboard.getOs = function () {\n    generate_os_data(\"proc/kernel/version\", \"#os-info\");\n    generate_os_data(\"proc/kernel/hostname\", \"#os-hostname\");\n    generate_os_data(\"system/date\", \"#os-time\");\n    generate_os_data(\"page/system/uptime\", \"#os-uptime\");\n\n    $.get(\"version\", function(d){\n        $(\"#agent-version\").text(d);\n    });\n}\n\ndashboard.getLoadAverage = function () {\n    $.get(\"page/system/loadavg\", function (d) {\n        if (d.msg != \"success\") {\n            return\n        }\n        $(\"#cpu-1min\").text(d.data[0][0]);\n        $(\"#cpu-5min\").text(d.data[1][0]);\n        $(\"#cpu-15min\").text(d.data[2][0]);\n        $(\"#cpu-1min-per\").text(d.data[0][1]);\n        $(\"#cpu-5min-per\").text(d.data[1][1]);\n        $(\"#cpu-15min-per\").text(d.data[2][1]);\n    }, \"json\");\n    generate_os_data(\"proc/cpu/num\", \"#core-number\");\n}\n\n/**\n * Refreshes all widgets. Does not call itself recursively.\n */\ndashboard.getAll = function () {\n    for (var item in dashboard.fnMap) {\n        if (dashboard.fnMap.hasOwnProperty(item) && item !== \"all\") {\n            dashboard.fnMap[item]();\n        }\n    }\n}\n\ndashboard.fnMap = {\n    all: dashboard.getAll,\n    ram: dashboard.getRam,\n    df: dashboard.getDf,\n    os: dashboard.getOs,\n    load: dashboard.getLoadAverage,\n    cpu: dashboard.getCpu,\n    diskstats: dashboard.getDiskstats,\n};\n"
  },
  {
    "path": "modules/agent/public/js/jquery.js",
    "content": "/*! jQuery v1.7.2 jquery.com | jquery.org/license */\n(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f(\"<\"+a+\">\").appendTo(b),e=d.css(\"display\");d.remove();if(e===\"none\"||e===\"\"){ck||(ck=c.createElement(\"iframe\"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?\"<!doctype html>\":\"\")+\"<html><body>\"),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,\"display\"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==\"string\"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k===\"*\")k=l;else if(l!==\"*\"&&l!==k){m=l+\" \"+k,n=e[m]||e[\"* \"+k];if(!n){p=b;for(o in e){j=o.split(\" \");if(j[0]===l||j[0]===\"*\"){p=e[j[1]+\" \"+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error(\"No conversion from \"+m.replace(\" \",\" to \")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function ca(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]===\"*\")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader(\"content-type\"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+\" \"+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function b_(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bD.test(a)?d(a,e):b_(a+\"[\"+(typeof e==\"object\"?b:\"\")+\"]\",e,c,d)});else if(!c&&f.type(b)===\"object\")for(var e in b)b_(a+\"[\"+e+\"]\",b[e],c,d);else d(a,b)}function b$(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bZ(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bS,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==\"string\"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bZ(a,c,d,e,l,g)));(k||!l)&&!g[\"*\"]&&(l=bZ(a,c,d,e,\"*\",g));return l}function bY(a){return function(b,c){typeof b!=\"string\"&&(c=b,b=\"*\");if(f.isFunction(c)){var d=b.toLowerCase().split(bO),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\\+/.test(h),j&&(h=h.substr(1)||\"*\"),i=a[h]=a[h]||[],i[j?\"unshift\":\"push\"](c)}}}function bB(a,b,c){var d=b===\"width\"?a.offsetWidth:a.offsetHeight,e=b===\"width\"?1:0,g=4;if(d>0){if(c!==\"border\")for(;e<g;e+=2)c||(d-=parseFloat(f.css(a,\"padding\"+bx[e]))||0),c===\"margin\"?d+=parseFloat(f.css(a,c+bx[e]))||0:d-=parseFloat(f.css(a,\"border\"+bx[e]+\"Width\"))||0;return d+\"px\"}d=by(a,b);if(d<0||d==null)d=a.style[b];if(bt.test(d))return d;d=parseFloat(d)||0;if(c)for(;e<g;e+=2)d+=parseFloat(f.css(a,\"padding\"+bx[e]))||0,c!==\"padding\"&&(d+=parseFloat(f.css(a,\"border\"+bx[e]+\"Width\"))||0),c===\"margin\"&&(d+=parseFloat(f.css(a,c+bx[e]))||0);return d+\"px\"}function bo(a){var b=c.createElement(\"div\");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||\"\").toLowerCase();b===\"input\"?bm(a):b!==\"script\"&&typeof a.getElementsByTagName!=\"undefined\"&&f.grep(a.getElementsByTagName(\"input\"),bm)}function bm(a){if(a.type===\"checkbox\"||a.type===\"radio\")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!=\"undefined\"?a.getElementsByTagName(\"*\"):typeof a.querySelectorAll!=\"undefined\"?a.querySelectorAll(\"*\"):[]}function bk(a,b){var c;b.nodeType===1&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c===\"object\"?b.outerHTML=a.outerHTML:c!==\"input\"||a.type!==\"checkbox\"&&a.type!==\"radio\"?c===\"option\"?b.selected=a.defaultSelected:c===\"input\"||c===\"textarea\"?b.defaultValue=a.defaultValue:c===\"script\"&&b.text!==a.text&&(b.text=a.text):(a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value)),b.removeAttribute(f.expando),b.removeAttribute(\"_submit_attached\"),b.removeAttribute(\"_change_attached\"))}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c,i[c][d])}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,\"table\")?a.getElementsByTagName(\"tbody\")[0]||a.appendChild(a.ownerDocument.createElement(\"tbody\")):a}function U(a){var b=V.split(\"|\"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b==\"string\"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+\"defer\",e=b+\"queue\",g=b+\"mark\",h=f._data(a,d);h&&(c===\"queue\"||!f._data(a,e))&&(c===\"mark\"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b===\"data\"&&f.isEmptyObject(a[b]))continue;if(b!==\"toJSON\")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e=\"data-\"+c.replace(k,\"-$1\").toLowerCase();d=a.getAttribute(e);if(typeof d==\"string\"){try{d=d===\"true\"?!0:d===\"false\"?!1:d===\"null\"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll(\"left\")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]*)$)/,j=/\\S/,k=/^\\s+/,l=/\\s+$/,m=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,n=/^[\\],:{}\\s]*$/,o=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,q=/(?:^|:|,)(?:\\s*\\[)+/g,r=/(webkit)[ \\/]([\\w.]+)/,s=/(opera)(?:.*version)?[ \\/]([\\w.]+)/,t=/(msie) ([\\w.]+)/,u=/(mozilla)(?:.*? rv:([\\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+\"\").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a===\"body\"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a==\"string\"){a.charAt(0)!==\"<\"||a.charAt(a.length-1)!==\">\"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:\"\",jquery:\"1.7.2\",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b===\"find\"?d.selector=this.selector+(this.selector?\" \":\"\")+c:b&&(d.selector=this.selector+\".\"+b+\"(\"+c+\")\");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),\"slice\",F.call(arguments).join(\",\"))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==\"boolean\"&&(l=i,i=arguments[1]||{},j=2),typeof i!=\"object\"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger(\"ready\").off(\"ready\")}},bindReady:function(){if(!A){A=e.Callbacks(\"once memory\");if(c.readyState===\"complete\")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener(\"DOMContentLoaded\",B,!1),a.addEventListener(\"load\",e.ready,!1);else if(c.attachEvent){c.attachEvent(\"onreadystatechange\",B),a.attachEvent(\"onload\",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)===\"function\"},isArray:Array.isArray||function(a){return e.type(a)===\"array\"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||\"object\"},isPlainObject:function(a){if(!a||e.type(a)!==\"object\"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,\"constructor\")&&!D.call(a.constructor.prototype,\"isPrototypeOf\"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!=\"string\"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,\"@\").replace(p,\"]\").replace(q,\"\")))return(new Function(\"return \"+b))();e.error(\"Invalid JSON: \"+b)},parseXML:function(c){if(typeof c!=\"string\"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,\"text/xml\")):(d=new ActiveXObject(\"Microsoft.XMLDOM\"),d.async=\"false\",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName(\"parsererror\").length)&&e.error(\"Invalid XML: \"+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,\"ms-\").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?\"\":G.call(a)}:function(a){return a==null?\"\":(a+\"\").replace(k,\"\").replace(l,\"\")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d===\"string\"||d===\"function\"||d===\"regexp\"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length==\"number\")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j==\"number\"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c==\"string\"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h,i){var j,k=d==null,l=0,m=a.length;if(d&&typeof d==\"object\"){for(l in d)e.access(a,c,l,d[l],1,h,f);g=1}else if(f!==b){j=i===b&&e.isFunction(f),k&&(j?(j=c,c=function(a,b,c){return j.call(e(a),c)}):(c.call(a,f),c=null));if(c)for(;l<m;l++)c(a[l],d,j?f.call(a[l],l,c(a[l],d)):f,i);g=1}return g?a:k?c.call(a):m?c(a[0],d):h},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf(\"compatible\")<0&&u.exec(a)||[];return{browser:b[1]||\"\",version:b[2]||\"0\"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"),function(a,b){I[\"[object \"+b+\"]\"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(\" \")&&(k=/^[\\s\\xA0]+/,l=/[\\s\\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener(\"DOMContentLoaded\",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState===\"complete\"&&(c.detachEvent(\"onreadystatechange\",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m,n=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h===\"array\"?n(g):h===\"function\"&&(!a.unique||!p.has(g))&&c.push(g)},o=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,j=!0,m=k||0,k=0,l=c.length;for(;c&&m<l;m++)if(c[m].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}j=!1,c&&(a.once?e===!0?p.disable():c=[]:d&&d.length&&(e=d.shift(),p.fireWith(e[0],e[1])))},p={add:function(){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){j&&f<=l&&(l--,f<=m&&m--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&p.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(j?a.once||d.push([b,c]):(!a.once||!e)&&o(b,c));return this},fire:function(){p.fireWith(this,arguments);return this},fired:function(){return!!i}};return p};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks(\"once memory\"),c=f.Callbacks(\"once memory\"),d=f.Callbacks(\"memory\"),e=\"pending\",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,\"resolve\"],fail:[b,\"reject\"],progress:[c,\"notify\"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+\"With\"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+\"With\"]=g[j].fireWith;i.done(function(){e=\"resolved\"},c.disable,d.lock).fail(function(){e=\"rejected\"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p=c.createElement(\"div\"),q=c.documentElement;p.setAttribute(\"className\",\"t\"),p.innerHTML=\"   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>\",d=p.getElementsByTagName(\"*\"),e=p.getElementsByTagName(\"a\")[0];if(!d||!d.length||!e)return{};g=c.createElement(\"select\"),h=g.appendChild(c.createElement(\"option\")),i=p.getElementsByTagName(\"input\")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName(\"tbody\").length,htmlSerialize:!!p.getElementsByTagName(\"link\").length,style:/top/.test(e.getAttribute(\"style\")),hrefNormalized:e.getAttribute(\"href\")===\"/a\",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value===\"on\",optSelected:h.selected,getSetAttribute:p.className!==\"t\",enctype:!!c.createElement(\"form\").enctype,html5Clone:c.createElement(\"nav\").cloneNode(!0).outerHTML!==\"<:nav></:nav>\",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode===\"CSS1Compat\",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent(\"onclick\",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent(\"onclick\")),i=c.createElement(\"input\"),i.value=\"t\",i.setAttribute(\"type\",\"radio\"),b.radioValue=i.value===\"t\",i.setAttribute(\"checked\",\"checked\"),i.setAttribute(\"name\",\"t\"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m=\"on\"+n,o=m in p,o||(p.setAttribute(m,\"return;\"),o=typeof p[m]==\"function\"),b[n+\"Bubbles\"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName(\"body\")[0];!u||(m=1,t=\"padding:0;margin:0;border:\",r=\"position:absolute;top:0;left:0;width:1px;height:1px;\",s=t+\"0;visibility:hidden;\",n=\"style='\"+r+t+\"5px solid #000;\",q=\"<div \"+n+\"display:block;'><div style='\"+t+\"0;display:block;overflow:hidden;'></div></div>\"+\"<table \"+n+\"' cellpadding='0' cellspacing='0'>\"+\"<tr><td></td></tr></table>\",d=c.createElement(\"div\"),d.style.cssText=s+\"width:0;height:0;position:static;top:0;margin-top:\"+m+\"px\",u.insertBefore(d,u.firstChild),p=c.createElement(\"div\"),d.appendChild(p),p.innerHTML=\"<table><tr><td style='\"+t+\"0;display:none'></td><td>t</td></tr></table>\",k=p.getElementsByTagName(\"td\"),o=k[0].offsetHeight===0,k[0].style.display=\"\",k[1].style.display=\"none\",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML=\"\",l=c.createElement(\"div\"),l.style.width=\"0\",l.style.marginRight=\"0\",p.style.width=\"2px\",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!=\"undefined\"&&(p.innerHTML=\"\",p.style.width=p.style.padding=\"1px\",p.style.border=0,p.style.overflow=\"hidden\",p.style.display=\"inline\",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display=\"block\",p.style.overflow=\"visible\",p.innerHTML=\"<div style='width:5px;'></div>\",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position=\"fixed\",g.style.top=\"20px\",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top=\"\",e.style.overflow=\"hidden\",e.style.position=\"relative\",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop=\"1%\",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!==\"1%\"),typeof d.style.zoom!=\"undefined\"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\\{.*\\}|\\[.*\\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:\"jQuery\"+(f.fn.jquery+Math.random()).replace(/\\D/g,\"\"),noData:{embed:!0,object:\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c==\"string\",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c===\"events\";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c==\"object\"||typeof c==\"function\")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(\" \")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute(\"classid\")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h,i,j=this[0],k=0,m=null;if(a===b){if(this.length){m=f.data(j);if(j.nodeType===1&&!f._data(j,\"parsedAttrs\")){g=j.attributes;for(i=g.length;k<i;k++)h=g[k].name,h.indexOf(\"data-\")===0&&(h=f.camelCase(h.substring(5)),l(j,h,m[h]));f._data(j,\"parsedAttrs\",!0)}}return m}if(typeof a==\"object\")return this.each(function(){f.data(this,a)});d=a.split(\".\",2),d[1]=d[1]?\".\"+d[1]:\"\",e=d[1]+\"!\";return f.access(this,function(c){if(c===b){m=this.triggerHandler(\"getData\"+e,[d[0]]),m===b&&j&&(m=f.data(j,a),m=l(j,a,m));return m===b&&d[1]?this.data(d[0]):m}d[1]=c,this.each(function(){var b=f(this);b.triggerHandler(\"setData\"+e,d),f.data(this,a,c),b.triggerHandler(\"changeData\"+e,d)})},null,c,arguments.length>1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||\"fx\")+\"mark\",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||\"fx\";var d=c+\"mark\",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,\"mark\"))}},queue:function(a,b,c){var d;if(a){b=(b||\"fx\")+\"queue\",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||\"fx\";var c=f.queue(a,b),d=c.shift(),e={};d===\"inprogress\"&&(d=c.shift()),d&&(b===\"fx\"&&c.unshift(\"inprogress\"),f._data(a,b+\".run\",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+\"queue \"+b+\".run\",!0),n(a,b,\"queue\"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!=\"string\"&&(c=a,a=\"fx\",d--);if(arguments.length<d)return f.queue(this[0],a);return c===b?this:this.each(function(){var b=f.queue(this,a,c);a===\"fx\"&&b[0]!==\"inprogress\"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||\"fx\";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||\"fx\",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!=\"string\"&&(c=a,a=b),a=a||\"fx\";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+\"defer\",j=a+\"queue\",k=a+\"mark\",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks(\"once memory\"),!0))h++,l.add(m);m();return d.promise(c)}});var o=/[\\n\\t\\r]/g,p=/\\s+/,q=/\\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,f.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a==\"string\"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=\" \"+e.className+\" \";for(h=0,i=b.length;h<i;h++)~g.indexOf(\" \"+b[h]+\" \")||(g+=b[h]+\" \");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a==\"string\"||a===b){c=(a||\"\").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(\" \"+g.className+\" \").replace(o,\" \");for(i=0,j=c.length;i<j;i++)h=h.replace(\" \"+c[i]+\" \",\" \");g.className=f.trim(h)}else g.className=\"\"}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b==\"boolean\";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c===\"string\"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?\"addClass\":\"removeClass\"](e)}else if(c===\"undefined\"||c===\"boolean\")this.className&&f._data(this,\"__className__\",this.className),this.className=this.className||a===!1?\"\":f._data(this,\"__className__\")||\"\"})},hasClass:function(a){var b=\" \"+a+\" \",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(\" \"+this[c].className+\" \").replace(o,\" \").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h=\"\":typeof h==\"number\"?h+=\"\":f.isArray(h)&&(h=f.map(h,function(a){return a==null?\"\":a+\"\"})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!(\"set\"in c)||c.set(this,h,\"value\")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&\"get\"in c&&(d=c.get(g,\"value\"))!==b)return d;d=g.value;return typeof d==\"string\"?d.replace(q,\"\"):d==null?\"\":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type===\"select-one\";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute(\"disabled\")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,\"optgroup\"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find(\"option\").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute==\"undefined\")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&\"set\"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,\"\"+d);return d}if(h&&\"get\"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i<g;i++)e=d[i],e&&(c=f.propFix[e]||e,h=u.test(e),h||f.attr(a,e,\"\"),a.removeAttribute(v?e:c),h&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error(\"type property can't be changed\");else if(!f.support.radioValue&&b===\"radio\"&&f.nodeName(a,\"input\")){var c=a.value;a.setAttribute(\"type\",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,\"button\"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,\"button\"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:\"tabIndex\",readonly:\"readOnly\",\"for\":\"htmlFor\",\"class\":\"className\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",cellpadding:\"cellPadding\",rowspan:\"rowSpan\",colspan:\"colSpan\",usemap:\"useMap\",frameborder:\"frameBorder\",contenteditable:\"contentEditable\"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&\"set\"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&\"get\"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode(\"tabindex\");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!=\"boolean\"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0,coords:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!==\"\":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+\"\"}},f.attrHooks.tabindex.set=w.set,f.each([\"width\",\"height\"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===\"\"){a.setAttribute(b,\"auto\");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===\"\"&&(b=\"false\"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each([\"href\",\"src\",\"width\",\"height\"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=\"\"+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype=\"encoding\"),f.support.checkOn||f.each([\"radio\",\"checkbox\"],function(){f.valHooks[this]={get:function(a){return a.getAttribute(\"value\")===null?\"on\":a.value}}}),f.each([\"radio\",\"checkbox\"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\\.]*)?(?:\\.(.+))?$/,B=/(?:^|\\s)hover(\\.\\S+)?\\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\\w*)(?:#([\\w\\-]+))?(?:\\.([\\w\\-]+))?$/,G=function(\na){var b=F.exec(a);b&&(b[1]=(b[1]||\"\").toLowerCase(),b[3]=b[3]&&new RegExp(\"(?:^|\\\\s)\"+b[3]+\"(?:\\\\s|$)\"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c[\"class\"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,\"mouseenter$1 mouseleave$1\")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!=\"undefined\"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(\" \");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||\"\").split(\".\").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:g&&G(g),namespace:n.join(\".\")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent(\"on\"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||\"\")).split(\" \");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp(\"(^|\\\\.)\"+l.split(\".\").sort().join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d===\"**\"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,[\"events\",\"handle\"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf(\"!\")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(\".\")>=0&&(i=h.split(\".\"),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c==\"object\"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join(\".\"),c.namespace_re=c.namespace?new RegExp(\"(^|\\\\.)\"+i.join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\"):null,o=h.indexOf(\":\")<0?\"on\"+h:\"\";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,\"events\")||{})[c.type]&&f._data(m,\"handle\"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!==\"click\"||!f.nodeName(e,\"a\"))&&f.acceptData(e)&&o&&e[h]&&(h!==\"focus\"&&h!==\"blur\"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,\"events\")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=f.event.special[c.type]||{},j=[],k,l,m,n,o,p,q,r,s,t,u;g[0]=c,c.delegateTarget=this;if(!i.preDispatch||i.preDispatch.call(this,c)!==!1){if(e&&(!c.button||c.type!==\"click\")){n=f(this),n.context=this.ownerDocument||this;for(m=c.target;m!=this;m=m.parentNode||this)if(m.disabled!==!0){p={},r=[],n[0]=m;for(k=0;k<e;k++)s=d[k],t=s.selector,p[t]===b&&(p[t]=s.quick?H(m,s.quick):n.is(t)),p[t]&&r.push(s);r.length&&j.push({elem:m,matches:r})}}d.length>e&&j.push({elem:this,matches:d.slice(e)});for(k=0;k<j.length&&!c.isPropagationStopped();k++){q=j[k],c.currentTarget=q.elem;for(l=0;l<q.matches.length&&!c.isImmediatePropagationStopped();l++){s=q.matches[l];if(h||!c.namespace&&!s.namespace||c.namespace_re&&c.namespace_re.test(s.namespace))c.data=s.data,c.handleObj=s,o=((f.event.special[s.origType]||{}).handle||s.handler).apply(q.elem,g),o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()))}}i.postDispatch&&i.postDispatch.call(this,c);return c.result}},props:\"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),fixHooks:{},keyHooks:{props:\"char charCode key keyCode\".split(\" \"),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:\"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:\"focusin\"},blur:{delegateType:\"focusout\"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent(\"on\"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,\"form\"))return!1;f.event.add(this,\"click._submit keypress._submit\",function(a){var c=a.target,d=f.nodeName(c,\"input\")||f.nodeName(c,\"button\")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,\"submit._submit\",function(a){a._submit_bubble=!0}),d._submit_attached=!0)})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&f.event.simulate(\"submit\",this.parentNode,a,!0))},teardown:function(){if(f.nodeName(this,\"form\"))return!1;f.event.remove(this,\"._submit\")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type===\"checkbox\"||this.type===\"radio\")f.event.add(this,\"propertychange._change\",function(a){a.originalEvent.propertyName===\"checked\"&&(this._just_changed=!0)}),f.event.add(this,\"click._change\",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate(\"change\",this,a,!0))});return!1}f.event.add(this,\"beforeactivate._change\",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,\"change._change\",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate(\"change\",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!==\"radio\"&&b.type!==\"checkbox\")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,\"._change\");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a==\"object\"){typeof c!=\"string\"&&(d=d||c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c==\"string\"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.origType+\".\"+e.namespace:e.origType,e.selector,e.handler);return this}if(typeof a==\"object\"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c==\"function\")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||\"**\",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,\"**\"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,\"lastToggle\"+a.guid)||0)%d;f._data(this,\"lastToggle\"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu\".split(\" \"),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!=\"string\"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,d=\"sizcache\"+(Math.random()+\"\").replace(\".\",\"\"),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\\\/g,k=/\\r\\n/g,l=/\\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=\"string\")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(\"\"),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]===\"~\"||w[0]===\"+\")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q=\"\",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)===\"[object Array]\")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!==\"\\\\\"){g[1]=(g[1]||\"\").replace(j,\"\"),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],\"\");break}}}}d||(d=typeof b.getElementsByTagName!=\"undefined\"?b.getElementsByTagName(\"*\"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)===\"\\\\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],\"\");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error(\"Syntax error, unrecognized expression: \"+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e=\"\";if(d){if(d===1||d===9||d===11){if(typeof a.textContent==\"string\")return a.textContent;if(typeof a.innerText==\"string\")return a.innerText.replace(k,\"\");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:[\"ID\",\"NAME\",\"TAG\"],match:{ID:/#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,CLASS:/\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,NAME:/\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,ATTR:/\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(?:(['\"])(.*?)\\3|(#?(?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)*)|)|)\\s*\\]/,TAG:/^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\\(\\s*(even|odd|(?:[+\\-]?\\d+|(?:[+\\-]?\\d*)?n\\s*(?:[+\\-]\\s*\\d+)?))\\s*\\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,PSEUDO:/:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/},leftMatch:{},attrMap:{\"class\":\"className\",\"for\":\"htmlFor\"},attrHandle:{href:function(a){return a.getAttribute(\"href\")},type:function(a){return a.getAttribute(\"type\")}},relative:{\"+\":function(a,b){var c=typeof b==\"string\",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},\">\":function(a,b){var c,d=typeof b==\"string\",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},\"\":function(a,b,c){var d,f=e++,g=x;typeof b==\"string\"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g(\"parentNode\",b,f,a,d,c)},\"~\":function(a,b,c){var d,f=e++,g=x;typeof b==\"string\"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g(\"previousSibling\",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!=\"undefined\"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!=\"undefined\"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute(\"name\")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!=\"undefined\")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=\" \"+a[1].replace(j,\"\")+\" \";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(\" \"+h.className+\" \").replace(/[\\t\\n\\r]/g,\" \").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,\"\")},TAG:function(a,b){return a[1].replace(j,\"\").toLowerCase()},CHILD:function(a){if(a[1]===\"nth\"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\\+|\\s*/g,\"\");var b=/(-?)(\\d*)(?:n([+\\-]?\\d*))?/.exec(a[2]===\"even\"&&\"2n\"||a[2]===\"odd\"&&\"2n+1\"||!/\\D/.test(a[2])&&\"0n+\"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,\"\");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||\"\").replace(j,\"\"),a[2]===\"~=\"&&(a[4]=\" \"+a[4]+\" \");return a},PSEUDO:function(b,c,d,e,f){if(b[1]===\"not\")if((a.exec(b[3])||\"\").length>1||/^\\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!==\"hidden\"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute(\"type\"),c=a.type;return a.nodeName.toLowerCase()===\"input\"&&\"text\"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"radio\"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"checkbox\"===a.type},file:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"file\"===a.type},password:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"password\"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b===\"input\"||b===\"button\")&&\"submit\"===a.type},image:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"image\"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b===\"input\"||b===\"button\")&&\"reset\"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b===\"input\"&&\"button\"===a.type||b===\"button\"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e===\"contains\")return(a.textContent||a.innerText||n([a])||\"\").indexOf(b[3])>=0;if(e===\"not\"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case\"only\":case\"first\":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k===\"first\")return!0;l=a;case\"last\":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case\"nth\":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute(\"id\")===b},TAG:function(a,b){return b===\"*\"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(\" \"+(a.className||a.getAttribute(\"class\"))+\" \").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+\"\",f=b[2],g=b[4];return d==null?f===\"!=\":!f&&m.attr?d!=null:f===\"=\"?e===g:f===\"*=\"?e.indexOf(g)>=0:f===\"~=\"?(\" \"+e+\" \").indexOf(g)>=0:g?f===\"!=\"?e!==g:f===\"^=\"?e.indexOf(g)===0:f===\"$=\"?e.substr(e.length-g.length)===g:f===\"|=\"?e===g||e.substr(0,g.length+1)===g+\"-\":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return\"\\\\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\\[]*\\])(?![^\\(]*\\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\\r|\\n)*?)/.source+o.match[r].source.replace(/\\\\(\\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)===\"[object Array]\")Array.prototype.push.apply(d,a);else if(typeof a.length==\"number\")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement(\"div\"),d=\"script\"+(new Date).getTime(),e=c.documentElement;a.innerHTML=\"<a name='\"+d+\"'/>\",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!=\"undefined\"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=\"undefined\"&&e.getAttributeNode(\"id\").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=\"undefined\"&&a.getAttributeNode(\"id\");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement(\"div\");a.appendChild(c.createComment(\"\")),a.getElementsByTagName(\"*\").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]===\"*\"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML=\"<a href='#'></a>\",a.firstChild&&typeof a.firstChild.getAttribute!=\"undefined\"&&a.firstChild.getAttribute(\"href\")!==\"#\"&&(o.attrHandle.href=function(a){return a.getAttribute(\"href\",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement(\"div\"),d=\"__sizzle__\";b.innerHTML=\"<p class='TEST'></p>\";if(!b.querySelectorAll||b.querySelectorAll(\".TEST\").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\\w+$)|^\\.([\\w\\-]+$)|^#([\\w\\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b===\"body\"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!==\"object\"){var k=e,l=e.getAttribute(\"id\"),n=l||d,p=e.parentNode,q=/^\\s*[+~]/.test(b);l?n=n.replace(/'/g,\"\\\\$&\"):e.setAttribute(\"id\",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll(\"[id='\"+n+\"'] \"+b),f)}catch(r){}finally{l||k.removeAttribute(\"id\")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement(\"div\"),\"div\"),e=!1;try{b.call(c.documentElement,\"[test!='']:sizzle\")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g,\"='$1']\");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement(\"div\");a.innerHTML=\"<div class='test e'></div><div class='test'></div>\";if(!!a.getElementsByClassName&&a.getElementsByClassName(\"e\").length!==0){a.lastChild.className=\"e\";if(a.getElementsByClassName(\"e\").length===1)return;o.order.splice(1,0,\"CLASS\"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=\"undefined\"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!==\"HTML\":!1};var y=function(a,b,c){var d,e=[],f=\"\",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,\"\");a=o.relative[a]?a+\"*\":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[\":\"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\\[\\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.globalPOS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!=\"string\")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack(\"\",\"find\",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),\"not\",a)},filter:function(a){return this.pushStack(T(this,a,!0),\"filter\",a)},is:function(a){return!!a&&(typeof a==\"string\"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!=\"string\"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,\"closest\",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a==\"string\")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==\"string\"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,\"parentNode\")},parentsUntil:function(a,b,c){return f.dir(a,\"parentNode\",c)},next:function(a){return f.nth(a,2,\"nextSibling\")},prev:function(a){return f.nth(a,2,\"previousSibling\")},nextAll:function(a){return f.dir(a,\"nextSibling\")},prevAll:function(a){return f.dir(a,\"previousSibling\")},nextUntil:function(a,b,c){return f.dir(a,\"nextSibling\",c)},prevUntil:function(a,b,c){return f.dir(a,\"previousSibling\",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,\"iframe\")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d==\"string\"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(\",\"))}}),f.extend({filter:function(a,b,c){c&&(a=\":not(\"+a+\")\");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V=\"abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",W=/ jQuery\\d+=\"(?:\\d+|null)\"/g,X=/^\\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,Z=/<([\\w:]+)/,$=/<tbody/i,_=/<|&#?\\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp(\"<(?:\"+V+\")[\\\\s/>]\",\"i\"),bd=/checked\\s*(?:[^=]|=\\s*.checked.)/i,be=/\\/(java|ecma)script/i,bf=/^\\s*<!(?:\\[CDATA\\[|\\-\\-)/,bg={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],area:[1,\"<map>\",\"</map>\"],_default:[0,\"\",\"\"]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,\"div<div>\",\"</div>\"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,\"body\")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f\n.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,\"before\",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,\"after\",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName(\"*\")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName(\"*\"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,\"\"):null;if(typeof a==\"string\"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||[\"\",\"\"])[1].toLowerCase()]){a=a.replace(Y,\"<$1></$2>\");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(f.cleanData(c.getElementsByTagName(\"*\")),c.innerHTML=a);c=0}catch(g){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!=\"string\"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),\"replaceWith\",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j==\"string\"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,\"tr\");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,function(a,b){b.src?f.ajax({type:\"GET\",global:!1,url:b.src,async:!1,dataType:\"script\"}):f.globalEval((b.text||b.textContent||b.innerHTML||\"\").replace(bf,\"/*$0*/\")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j==\"string\"&&j.length<512&&i===c&&j.charAt(0)===\"<\"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test(\"<\"+a.nodeName+\">\")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement==\"undefined\"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l==\"number\"&&(l+=\"\");if(!l)continue;if(typeof l==\"string\")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,\"<$1></$2>\");var m=(Z.exec(l)||[\"\",\"\"])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement(\"div\"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m===\"table\"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]===\"<table>\"&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],\"tbody\")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)==\"number\")for(i=0;i<u;i++)bn(l[i]);else bn(l);l.nodeType?j.push(l):j=f.merge(j,l)}if(d){g=function(a){return!a.type||be.test(a.type)};for(k=0;j[k];k++){h=j[k];if(e&&f.nodeName(h,\"script\")&&(!h.type||be.test(h.type)))e.push(h.parentNode?h.parentNode.removeChild(h):h);else{if(h.nodeType===1){var v=f.grep(h.getElementsByTagName(\"script\"),g);j.splice.apply(j,[k+1,0].concat(v))}d.appendChild(h)}}}return j},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bp=/alpha\\([^)]*\\)/i,bq=/opacity=([^)]*)/,br=/([A-Z]|^ms)/g,bs=/^[\\-+]?(?:\\d*\\.)?\\d+$/i,bt=/^-?(?:\\d*\\.)?\\d+(?!px)[^\\d\\s]+$/i,bu=/^([\\-+])=([\\-+.\\de]+)/,bv=/^margin/,bw={position:\"absolute\",visibility:\"hidden\",display:\"block\"},bx=[\"Top\",\"Right\",\"Bottom\",\"Left\"],by,bz,bA;f.fn.css=function(a,c){return f.access(this,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)},a,c,arguments.length>1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,\"opacity\");return c===\"\"?\"1\":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":f.support.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&\"get\"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h===\"string\"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h=\"number\");if(d==null||h===\"number\"&&isNaN(d))return;h===\"number\"&&!f.cssNumber[i]&&(d+=\"px\");if(!k||!(\"set\"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c===\"cssFloat\"&&(c=\"float\");if(g&&\"get\"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,\"-$1\").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===\"\"&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b===\"fontSize\"?\"1em\":f,f=g.pixelLeft+\"px\",g.left=c,d&&(a.runtimeStyle.left=d));return f===\"\"?\"auto\":f}),by=bz||bA,f.each([\"height\",\"width\"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+\"px\":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||\"\")?parseFloat(RegExp.$1)/100+\"\":b?\"1\":\"\"},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?\"alpha(opacity=\"+b*100+\")\":\"\",g=d&&d.filter||c.filter||\"\";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,\"\"))===\"\"){c.removeAttribute(\"filter\");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+\" \"+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:\"inline-block\"},function(){return b?by(a,\"margin-right\"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,\"display\"))===\"none\"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:\"\",padding:\"\",border:\"Width\"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c==\"string\"?c.split(\" \"):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\\[\\]$/,bE=/\\r?\\n/g,bF=/#.*$/,bG=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\\-storage|.+\\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\\/\\//,bL=/\\?/,bM=/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\\w\\+\\.\\-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=[\"*/\"]+[\"*\"];try{bU=e.href}catch(bX){bU=c.createElement(\"a\"),bU.href=\"\",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!=\"string\"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(\" \");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h=\"GET\";c&&(f.isFunction(c)?(d=c,c=b):typeof c==\"object\"&&(c=f.param(c,f.ajaxSettings.traditional),h=\"POST\"));var i=this;f.ajax({url:a,type:h,dataType:\"html\",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f(\"<div>\").append(c.replace(bM,\"\")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,\"\\r\\n\")}}):{name:b.name,value:c.replace(bE,\"\\r\\n\")}}).get()}}),f.each(\"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split(\" \"),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each([\"get\",\"post\"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,\"script\")},getJSON:function(a,b,c){return f.get(a,b,c,\"json\")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:\"GET\",contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",processData:!0,async:!0,accepts:{xml:\"application/xml, text/xml\",html:\"text/html\",text:\"text/plain\",json:\"application/json, text/javascript\",\"*\":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:\"responseXML\",text:\"responseText\"},converters:{\"* text\":a.String,\"text html\":!0,\"text json\":f.parseJSON,\"text xml\":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||\"\",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader(\"Last-Modified\"))f.lastModified[k]=y;if(z=v.getResponseHeader(\"Etag\"))f.etag[k]=z}if(a===304)w=\"notmodified\",o=!0;else try{r=cb(d,x),w=\"success\",o=!0}catch(A){w=\"parsererror\",u=A}}else{u=w;if(!w||a)w=\"error\",a<0&&(a=0)}v.status=a,v.statusText=\"\"+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger(\"ajax\"+(o?\"Success\":\"Error\"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger(\"ajaxComplete\",[v,d]),--f.active||f.event.trigger(\"ajaxStop\"))}}typeof a==\"object\"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks(\"once memory\"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||\"abort\",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+\"\").replace(bF,\"\").replace(bK,bV[1]+\"//\"),d.dataTypes=f.trim(d.dataType||\"*\").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]===\"http:\"?80:443))==(bV[3]||(bV[1]===\"http:\"?80:443)))),d.data&&d.processData&&typeof d.data!=\"string\"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger(\"ajaxStart\");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?\"&\":\"?\")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,\"$1_=\"+x);d.url=y+(y===d.url?(bL.test(d.url)?\"&\":\"?\")+\"_=\"+x:\"\")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader(\"Content-Type\",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader(\"If-Modified-Since\",f.lastModified[k]),f.etag[k]&&v.setRequestHeader(\"If-None-Match\",f.etag[k])),v.setRequestHeader(\"Accept\",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!==\"*\"?\", \"+bW+\"; q=0.01\":\"\"):d.accepts[\"*\"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,\"No Transport\");else{v.readyState=1,t&&g.trigger(\"ajaxSend\",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort(\"timeout\")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+\"=\"+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join(\"&\").replace(bC,\"+\")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\\=)\\?(&|$)|\\?\\?/i;f.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){return f.expando+\"_\"+cc++}}),f.ajaxPrefilter(\"json jsonp\",function(b,c,d){var e=typeof b.data==\"string\"&&/^application\\/x\\-www\\-form\\-urlencoded/.test(b.contentType);if(b.dataTypes[0]===\"jsonp\"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l=\"$1\"+h+\"$2\";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\\?/.test(j)?\"&\":\"?\")+b.jsonp+\"=\"+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters[\"script json\"]=function(){g||f.error(h+\" was not called\");return g[0]},b.dataTypes[0]=\"json\";return\"script\"}}),f.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/javascript|ecmascript/},converters:{\"text script\":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter(\"script\",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type=\"GET\",a.global=!1)}),f.ajaxTransport(\"script\",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName(\"head\")[0]||c.documentElement;return{send:function(f,g){d=c.createElement(\"script\"),d.async=\"async\",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,\"success\")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&\"withCredentials\"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e[\"X-Requested-With\"]&&(e[\"X-Requested-With\"]=\"XMLHttpRequest\");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=\"\"}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\\-]=)?([\\d+.\\-]+)([a-z%]*)$/i,co,cp=[[\"height\",\"marginTop\",\"marginBottom\",\"paddingTop\",\"paddingBottom\"],[\"width\",\"marginLeft\",\"marginRight\",\"paddingLeft\",\"paddingRight\"],[\"opacity\"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct(\"show\",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,\"olddisplay\")&&e===\"none\"&&(e=d.style.display=\"\"),(e===\"\"&&f.css(d,\"display\")===\"none\"||!f.contains(d.ownerDocument.documentElement,d))&&f._data(d,\"olddisplay\",cu(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===\"\"||e===\"none\")d.style.display=f._data(d,\"olddisplay\")||\"\"}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(ct(\"hide\",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,\"display\"),e!==\"none\"&&!f._data(d,\"olddisplay\")&&f._data(d,\"olddisplay\",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display=\"none\");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a==\"boolean\";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(\":hidden\");f(this)[b?\"show\":\"hide\"]()}):this.animate(ct(\"toggle\",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(\":hidden\").css(\"opacity\",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(\":hidden\"),g,h,i,j,k,l,m,n,o,p,q;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]);if((k=f.cssHooks[g])&&\"expand\"in k){l=k.expand(a[g]),delete a[g];for(i in l)i in a||(a[i]=l[i])}}for(g in a){h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||\"swing\";if(h===\"hide\"&&d||h===\"show\"&&!d)return b.complete.call(this);c&&(g===\"height\"||g===\"width\")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,\"display\")===\"inline\"&&f.css(this,\"float\")===\"none\"&&(!f.support.inlineBlockNeedsLayout||cu(this.nodeName)===\"inline\"?this.style.display=\"inline-block\":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow=\"hidden\");for(i in a)j=new f.fx(this,b,i),h=a[i],cm.test(h)?(q=f._data(this,\"toggle\"+i)||(h===\"toggle\"?d?\"show\":\"hide\":0),q?(f._data(this,\"toggle\"+i,q===\"show\"?\"hide\":\"show\"),j[q]()):j[h]()):(m=cn.exec(h),n=j.cur(),m?(o=parseFloat(m[2]),p=m[3]||(f.cssNumber[i]?\"\":\"px\"),p!==\"px\"&&(f.style(this,i,(o||1)+p),n=(o||1)/j.cur()*n,f.style(this,i,n+p)),m[1]&&(o=(m[1]===\"-=\"?-1:1)*o+n),j.custom(n,o,p)):j.custom(n,h,\"\"));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!=\"string\"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||\"fx\",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(\".run\")===b.length-4&&h(this,g,b);else g[b=a+\".run\"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:ct(\"show\",1),slideUp:ct(\"hide\",1),slideToggle:ct(\"toggle\",1),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a==\"object\"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration==\"number\"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue=\"fx\";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a){return a},swing:function(a){return-Math.cos(a*Math.PI)/2+.5}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b===\"auto\"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cq||cr(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?\"\":\"px\"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){f._data(e.elem,\"fxshow\"+e.prop)===b&&(e.options.hide?f._data(e.elem,\"fxshow\"+e.prop,e.start):e.options.show&&f._data(e.elem,\"fxshow\"+e.prop,e.end))},h()&&f.timers.push(h)&&!co&&(co=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,\"fxshow\"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop===\"width\"||this.prop===\"height\"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,\"fxshow\"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cq||cr(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each([\"\",\"X\",\"Y\"],function(a,b){h.style[\"overflow\"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,\"fxshow\"+b,!0),f.removeData(h,\"toggle\"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(co),co=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,\"opacity\",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(cp.concat.apply([],cp),function(a,b){b.indexOf(\"margin\")&&(f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)})}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cv,cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;\"getBoundingClientRect\"in c.documentElement?cv=function(a,b,c,d){try{d=a.getBoundingClientRect()}catch(e){}if(!d||!f.contains(c,a))return d?{top:d.top,left:d.left}:{top:0,left:0};var g=b.body,h=cy(b),i=c.clientTop||g.clientTop||0,j=c.clientLeft||g.clientLeft||0,k=h.pageYOffset||f.support.boxModel&&c.scrollTop||g.scrollTop,l=h.pageXOffset||f.support.boxModel&&c.scrollLeft||g.scrollLeft,m=d.top+k-i,n=d.left+l-j;return{top:m,left:n}}:cv=function(a,b,c){var d,e=a.offsetParent,g=a,h=b.body,i=b.defaultView,j=i?i.getComputedStyle(a,null):a.currentStyle,k=a.offsetTop,l=a.offsetLeft;while((a=a.parentNode)&&a!==h&&a!==c){if(f.support.fixedPosition&&j.position===\"fixed\")break;d=i?i.getComputedStyle(a,null):a.currentStyle,k-=a.scrollTop,l-=a.scrollLeft,a===e&&(k+=a.offsetTop,l+=a.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(a.nodeName))&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),g=e,e=a.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&d.overflow!==\"visible\"&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),j=d}if(j.position===\"relative\"||j.position===\"static\")k+=h.offsetTop,l+=h.offsetLeft;f.support.fixedPosition&&j.position===\"fixed\"&&(k+=Math.max(c.scrollTop,h.scrollTop),l+=Math.max(c.scrollLeft,h.scrollLeft));return{top:k,left:l}},f.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){f.offset.setOffset(this,a,b)});var c=this[0],d=c&&c.ownerDocument;if(!d)return null;if(c===d.body)return f.offset.bodyOffset(c);return cv(c,d,d.documentElement)},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,\"marginTop\"))||0,c+=parseFloat(f.css(a,\"marginLeft\"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,\"position\");d===\"static\"&&(a.style.position=\"relative\");var e=f(a),g=e.offset(),h=f.css(a,\"top\"),i=f.css(a,\"left\"),j=(d===\"absolute\"||d===\"fixed\")&&f.inArray(\"auto\",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),\"using\"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,\"marginTop\"))||0,c.left-=parseFloat(f.css(a,\"marginLeft\"))||0,d.top+=parseFloat(f.css(b[0],\"borderTopWidth\"))||0,d.left+=parseFloat(f.css(b[0],\"borderLeftWidth\"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,\"position\")===\"static\")a=a.offsetParent;return a})}}),f.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:\"height\",Width:\"width\"},function(a,c){var d=\"client\"+a,e=\"scroll\"+a,g=\"offset\"+a;f.fn[\"inner\"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,\"padding\")):this[c]():null},f.fn[\"outer\"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?\"margin\":\"border\")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define==\"function\"&&define.amd&&define.amd.jQuery&&define(\"jquery\",[],function(){return f})})(window);"
  },
  {
    "path": "modules/agent/public/js/odometer.js",
    "content": "/*! odometer 0.3.6 */\n(function(){var 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;p='<span class=\"odometer-value\"></span>',m='<span class=\"odometer-ribbon\"><span class=\"odometer-ribbon-inner\">'+p+\"</span></span>\",d='<span class=\"odometer-digit\"><span class=\"odometer-digit-spacer\">8</span><span class=\"odometer-digit-inner\">'+m+\"</span></span>\",g='<span class=\"odometer-formatting-mark\"></span>',c=\",ddd\",h=60,f=2e3,a=20,i=2,e=.5,j=1e3/h,b=1e3/a,n=\"transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd\",t=document.createElement(\"div\").style,o=null!=t.transition||null!=t.webkitTransition||null!=t.mozTransition||null!=t.oTransition,s=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame,k=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver,q=function(a){var b;return b=document.createElement(\"div\"),b.innerHTML=a,b.children[0]},r=function(){var a,b;return null!=(a=null!=(b=window.performance)?b.now():void 0)?a:+new Date},v=!1,(u=function(){var a,b,c,d,e;if(!v&&null!=window.jQuery){for(v=!0,d=[\"html\",\"text\"],e=[],b=0,c=d.length;c>b;b++)a=d[b],e.push(function(a){var b;return b=window.jQuery.fn[a],window.jQuery.fn[a]=function(a){return null==a||null==this[0].odometer?b.apply(this,arguments):this[0].odometer.update(a)}}(a));return e}})(),setTimeout(u,0),l=function(){function a(b){var d,e,g,h,k,l,m,n,o,p,q,r,s,t,u,v=this;if(this.options=b,this.el=this.options.el,null!=this.el.odometer)return this.el.odometer;for(this.el.odometer=this,s=a.options,h=o=0,q=s.length;q>o;h=++o)e=s[h],null==this.options[e]&&(this.options[e]=h);this.value=this.cleanValue(null!=(t=this.options.value)?t:\"\"),null==(k=this.options).format&&(k.format=c),(l=this.options).format||(l.format=\"d\"),null==(m=this.options).duration&&(m.duration=f),this.MAX_VALUES=0|this.options.duration/j/i,this.renderInside(),this.render();try{for(u=[\"HTML\",\"Text\"],n=function(a){return Object.defineProperty(v.el,\"inner\"+a,{get:function(){return v.inside[\"outer\"+a]},set:function(a){return v.update(v.cleanValue(a))}})},p=0,r=u.length;r>p;p++)g=u[p],n(g)}catch(w){d=w,this.watchForMutations()}}return a.prototype.renderInside=function(){return this.inside=document.createElement(\"div\"),this.inside.className=\"odometer-inside\",this.el.innerHTML=\"\",this.el.appendChild(this.inside)},a.prototype.watchForMutations=function(){var a,b=this;if(null!=k)try{return null==this.observer&&(this.observer=new k(function(){var a;return a=b.el.innerText,b.renderInside(),b.render(b.value),b.update(a)})),this.watchMutations=!0,this.startWatchingMutations()}catch(c){a=c}},a.prototype.startWatchingMutations=function(){return this.watchMutations?this.observer.observe(this.el,{childList:!0}):void 0},a.prototype.stopWatchingMutations=function(){var a;return null!=(a=this.observer)?a.disconnect():void 0},a.prototype.cleanValue=function(a){return parseInt(a.toString().replace(/[.,]/g,\"\"),10)||0},a.prototype.bindTransitionEnd=function(){var a,b,c,d,e,f,g=this;if(!this.transitionEndBound){for(this.transitionEndBound=!0,b=!1,e=n.split(\" \"),f=[],c=0,d=e.length;d>c;c++)a=e[c],f.push(this.el.addEventListener(a,function(){return b?!0:(b=!0,setTimeout(function(){return g.render(),b=!1},0),!0)},!1));return f}},a.prototype.resetFormat=function(){return this.format=this.options.format.split(\"\").reverse().join(\"\")},a.prototype.render=function(a){var b,c,d,e,f,g,h,i,j;for(null==a&&(a=this.value),this.stopWatchingMutations(),this.resetFormat(),this.inside.innerHTML=\"\",b=this.el.className.split(\" \"),e=[],f=0,h=b.length;h>f;f++)c=b[f],c.length&&(/^odometer(-|$)/.test(c)||e.push(c));for(e.push(\"odometer\"),o||e.push(\"odometer-no-transitions\"),this.options.theme?e.push(\"odometer-theme-\"+this.options.theme):e.push(\"odometer-auto-theme\"),this.el.className=e.join(\" \"),this.ribbons={},this.digits=[],j=a.toString().split(\"\").reverse(),g=0,i=j.length;i>g;g++)d=j[g],this.addDigit(d);return this.startWatchingMutations()},a.prototype.update=function(a){var b,c=this;return a=this.cleanValue(a),(b=a-this.value)?(this.el.className+=b>0?\" odometer-animating-up\":\" odometer-animating-down\",this.stopWatchingMutations(),this.animate(a),this.startWatchingMutations(),setTimeout(function(){return c.el.offsetHeight,c.el.className+=\" odometer-animating\"},0),this.value=a):void 0},a.prototype.renderDigit=function(){return q(d)},a.prototype.insertDigit=function(a){return this.inside.children.length?this.inside.insertBefore(a,this.inside.children[0]):this.inside.appendChild(a)},a.prototype.addSpacer=function(a){var b;return b=q(g),b.innerHTML=a,this.insertDigit(b)},a.prototype.addDigit=function(a){var b,c,d;if(\"-\"===a)return this.addSpacer(\"-\"),void 0;for(d=!1;;){if(\"-\"===a)break;if(!this.format.length){if(d)throw new Error(\"Bad odometer format without digits\");this.resetFormat(),d=!0}if(b=this.format[0],this.format=this.format.substring(1),\"d\"===b)break;this.addSpacer(b)}return c=this.renderDigit(),c.querySelector(\".odometer-value\").innerHTML=a,this.digits.push(c),this.insertDigit(c)},a.prototype.animate=function(a){return o?this.animateSlide(a):this.animateCount(a)},a.prototype.animateCount=function(a){var c,d,e,f,g,h=this;if(d=+a-this.value)return f=e=r(),c=this.value,(g=function(){var i,j,k;return r()-f>h.options.duration?(h.value=a,h.render(),void 0):(i=r()-e,i>b&&(e=r(),k=i/h.options.duration,j=d*k,c+=j,h.render(Math.round(c))),null!=window.requestAnimationFrame?s(g):setTimeout(g,b))})()},a.prototype.animateSlide=function(a){var b,c,d,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y;if(d=a-this.value){for(this.bindTransitionEnd(),f=Math.ceil(Math.log(Math.max(Math.abs(a),Math.abs(this.value))+1)/Math.log(10)),g=[],b=0,l=r=0;f>=0?f>r:r>f;l=f>=0?++r:--r){if(p=Math.floor(this.value/Math.pow(10,f-l-1)),i=Math.floor(a/Math.pow(10,f-l-1)),h=i-p,Math.abs(h)>this.MAX_VALUES){for(k=[],m=h/(this.MAX_VALUES+this.MAX_VALUES*b*e),c=p;h>0&&i>c||0>h&&c>i;)k.push(Math.round(c)),c+=m;k[k.length-1]!==i&&k.push(i),b++}else k=function(){x=[];for(var a=p;i>=p?i>=a:a>=i;i>=p?a++:a--)x.push(a);return x}.apply(this);for(l=s=0,u=k.length;u>s;l=++s)j=k[l],k[l]=Math.abs(j%10);g.push(k)}for(w=g.reverse(),y=[],l=t=0,v=w.length;v>t;l=++t)k=w[l],this.digits[l]||this.addDigit(\" \"),null==(q=this.ribbons)[l]&&(q[l]=this.digits[l].querySelector(\".odometer-ribbon-inner\")),this.ribbons[l].innerHTML=\"\",0>d&&(k=k.reverse()),y.push(function(){var a,b,c;for(c=[],n=b=0,a=k.length;a>b;n=++b)j=k[n],o=document.createElement(\"div\"),o.className=\"odometer-value\",o.innerHTML=j,this.ribbons[l].appendChild(o),n===k.length-1&&(o.className+=\" odometer-last-value\"),0===n?c.push(o.className+=\" odometer-first-value\"):c.push(void 0);return c}.call(this));return y}},a}(),l.options=null!=(x=window.odometerOptions)?x:{},setTimeout(function(){var a,b,c,d,e;if(window.odometerOptions){d=window.odometerOptions,e=[];for(a in d)b=d[a],e.push(null!=(c=l.options)[a]?(c=l.options)[a]:c[a]=b);return e}},0),l.init=function(){var a,b,c,d,e;for(b=document.querySelectorAll(l.options.selector||\".odometer\"),e=[],c=0,d=b.length;d>c;c++)a=b[c],e.push(a.odometer=new l({el:a,value:a.innerText}));return e},null!=(null!=(y=document.documentElement)?y.doScroll:void 0)&&null!=document.createEventObject?(w=document.onreadystatechange,document.onreadystatechange=function(){return\"complete\"===document.readyState&&l.options.auto!==!1&&l.init(),null!=w?w.apply(this,arguments):void 0}):document.addEventListener(\"DOMContentLoaded\",function(){return l.options.auto!==!1?l.init():void 0},!1),window.Odometer=l}).call(this);"
  },
  {
    "path": "modules/agent/version.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// build !release\npackage main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  },
  {
    "path": "modules/aggregator/.gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n*.swp\n*.swo\n*.log\n.idea\n.DS_Store\n/var\n/falcon-aggregator*\n/aggregator*\n/cfg.json\n/gitversion\n\n"
  },
  {
    "path": "modules/aggregator/README.md",
    "content": "# Aggregator\n\n集群聚合模块。聚合某集群下的所有机器的某个指标的值，提供一种集群视角的监控体验。\n\n## 源码编译\n\n```bash\ncd $GOPATH/src/github.com/open-falcon\ngit clone https://github.com/open-falcon/sdk.git\ngit clone https://github.com/open-falcon/falcon-plus.git\ncd falcon-plus/modules/aggregator\ngo get \n./control build\n./control pack\n```\n\n最后一步会pack出一个tar.gz的安装包，拿着这个包去部署服务即可。\n\n## 服务部署\n服务部署，包括配置修改、启动服务、检验服务、停止服务等。这之前，需要将安装包解压到服务的部署目录下。\n\n```bash\n# 修改配置, 配置项含义见下文\nmv cfg.example.json cfg.json\nvim cfg.json\n\n# 启动服务\n./control start\n\n# 校验服务，看端口是否在监听\nss -tln\n\n# 检查log\n./control tail\n\n...\n# 停止服务\n./control stop\n\n```\n\n## 配置说明\n配置文件默认为./cfg.json。默认情况下，安装包会有一个cfg.example.json的配置文件示例。各配置项的含义，如下\n\n```bash\n## Configuration\n{\n    \"debug\": true,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:6055\"\n    },\n    \"database\": {\n        \"addr\": \"root:@tcp(127.0.0.1:3306)/falcon_portal?loc=Local&parseTime=true\",\n        \"idle\": 10,\n        \"ids\": [1,-1], # aggregator模块可以部署多个实例，这个配置表示当前实例要处理的数据库中cluster表的id范围\n        \"interval\": 55\n    },\n    \"api\": {\n        \"hostnames\": \"http://127.0.0.1:5050/api/group/%s/hosts.json\", # 注意修改为你的portal的ip:port\n        \"push\": \"http://127.0.0.1:6060/api/push\", # 注意修改为你的transfer的http ip:port\n        \"graphLast\": \"http://127.0.0.1:9966/graph/last\" # 注意修改为你的query的ip:port\n    }\n}\n       \n```\n"
  },
  {
    "path": "modules/aggregator/cfg.example.json",
    "content": "{\n    \"debug\": true,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:6055\"\n    },\n    \"database\": {\n        \"addr\": \"root:@tcp(127.0.0.1:3306)/falcon_portal?loc=Local&parseTime=true\",\n        \"idle\": 10,\n        \"ids\": [1, -1],\n        \"interval\": 55\n    },\n    \"api\": {\n        \"connect_timeout\": 500,\n        \"request_timeout\": 2000,\n        \"plus_api\": \"http://127.0.0.1:8080\",\n        \"plus_api_token\": \"default-token-used-in-server-side\",\n        \"push_api\": \"http://127.0.0.1:1988/v1/push\"\n    }\n}\n"
  },
  {
    "path": "modules/aggregator/control",
    "content": "#!/bin/bash\n\nWORKSPACE=$(cd $(dirname $0)/; pwd)\ncd $WORKSPACE\n\nmkdir -p var\n\nmodule=aggregator\napp=falcon-$module\nconf=cfg.json\npidfile=var/app.pid\nlogfile=var/app.log\n\nfunction check_pid() {\n    if [ -f $pidfile ];then\n        pid=`cat $pidfile`\n        if [ -n $pid ]; then\n            running=`ps -p $pid|grep -v \"PID TTY\" |wc -l`\n            return $running\n        fi\n    fi\n    return 0\n}\n\nfunction start() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running already, pid=\"\n        cat $pidfile\n        return 1\n    fi\n\n    nohup ./$app -c $conf >> $logfile 2>&1 &\n    echo $! > $pidfile\n    echo \"$app started..., pid=$!\"\n}\n\nfunction stop() {\n    pid=`cat $pidfile`\n    kill $pid\n    echo \"$app stopped...\"\n}\n\nfunction restart() {\n    stop\n    sleep 1\n    start\n}\n\nfunction status() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running, pid=\"\n        cat $pidfile\n    else\n        echo \"$app is stopped\"\n    fi\n}\n\nfunction tailf() {\n    tail -f $logfile\n}\n\nfunction build() {\n    go build\n    if [ $? -ne 0 ]; then\n        exit $?\n    fi\n    mv $module $app\n    ./$app -v\n}\n\nfunction pack() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-$version.tar.gz control cfg.example.json $app gitversion\n}\n\nfunction packbin() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-bin-$version.tar.gz $app gitversion\n}\n\nfunction help() {\n    echo \"$0 build|pack|packbin|start|stop|restart|status|tail\"\n}\n\nif [ \"$1\" == \"\" ]; then\n    help\nelif [ \"$1\" == \"stop\" ];then\n    stop\nelif [ \"$1\" == \"start\" ];then\n    start\nelif [ \"$1\" == \"restart\" ];then\n    restart\nelif [ \"$1\" == \"status\" ];then\n    status\nelif [ \"$1\" == \"tail\" ];then\n    tailf\nelif [ \"$1\" == \"build\" ];then\n    build\nelif [ \"$1\" == \"pack\" ];then\n    pack\nelif [ \"$1\" == \"packbin\" ];then\n    packbin\nelse\n    help\nfi\n"
  },
  {
    "path": "modules/aggregator/cron/computer.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"errors\"\n\t\"regexp\"\n\t\"strconv\"\n)\n\nfunc compute(operands []string, operators []string, computeMode string, hostname string, valMap map[string]float64) (val float64, err error) {\n\n\tcount := len(operands)\n\tif count == 0 {\n\t\treturn val, errors.New(\"counter not found\")\n\t}\n\n\tvals := queryOperands(operands, hostname, valMap)\n\tif len(vals) != count {\n\t\treturn val, errors.New(\"value invalid\")\n\t}\n\n\tsum := vals[0]\n\tfor i, v := range vals[1:] {\n\t\tif operators[i] == \"+\" {\n\t\t\tsum += v\n\t\t} else {\n\t\t\tsum -= v\n\t\t}\n\t}\n\n\tif computeMode != \"\" {\n\t\tif compareSum(sum, computeMode) {\n\t\t\tval = 1\n\t\t}\n\t} else {\n\t\tval = sum\n\t}\n\treturn val, nil\n}\n\nfunc compareSum(sum float64, computeMode string) bool {\n\n\tregMatch, _ := regexp.Compile(`([><=]+)([\\d\\.]+)`)\n\tmatch := regMatch.FindStringSubmatch(computeMode)\n\n\tmode := match[1]\n\tval, _ := strconv.ParseFloat(match[2], 64)\n\n\tswitch {\n\tcase mode == \">\" && sum > val:\n\tcase mode == \"<\" && sum < val:\n\tcase mode == \"=\" && sum == val:\n\tcase mode == \">=\" && sum >= val:\n\tcase mode == \"<=\" && sum <= val:\n\tdefault:\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc queryOperands(counters []string, endpoint string, valMap map[string]float64) []float64 {\n\tret := []float64{}\n\tfor _, counter := range counters {\n\t\tif v, ok := valMap[endpoint+counter]; ok {\n\t\t\tret = append(ret, v)\n\t\t}\n\t}\n\n\treturn ret\n}\n"
  },
  {
    "path": "modules/aggregator/cron/query.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/sdk\"\n)\n\nfunc queryCounterLast(numeratorOperands, denominatorOperands, hostnames []string, begin, end int64) (map[string]float64, error) {\n\tcounters := []string{}\n\n\tcounters = append(counters, numeratorOperands...)\n\tcounters = append(counters, denominatorOperands...)\n\n\tresp, err := sdk.QueryLastPoints(hostnames, counters)\n\tif err != nil {\n\t\treturn map[string]float64{}, err\n\t}\n\n\tret := make(map[string]float64)\n\tfor _, res := range resp {\n\t\tv := res.Value\n\t\tif v.Timestamp < begin || v.Timestamp > end {\n\t\t\tcontinue\n\t\t}\n\t\tret[res.Endpoint+res.Counter] = float64(v.Value)\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "modules/aggregator/cron/run.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"log\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/sdk/sender\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/sdk\"\n)\n\nfunc WorkerRun(item *g.Cluster) {\n\tdebug := g.Config().Debug\n\n\tnumeratorStr := cleanParam(item.Numerator)\n\tdenominatorStr := cleanParam(item.Denominator)\n\n\tif !expressionValid(numeratorStr) || !expressionValid(denominatorStr) {\n\t\tlog.Println(\"[W] invalid numerator or denominator\", item)\n\t\treturn\n\t}\n\n\tneedComputeNumerator := needCompute(numeratorStr)\n\tneedComputeDenominator := needCompute(denominatorStr)\n\n\tif !needComputeNumerator && !needComputeDenominator {\n\t\tlog.Println(\"[W] no need compute\", item)\n\t\treturn\n\t}\n\n\tnumeratorOperands, numeratorOperators, numeratorComputeMode := parse(numeratorStr, needComputeNumerator)\n\tdenominatorOperands, denominatorOperators, denominatorComputeMode := parse(denominatorStr, needComputeDenominator)\n\n\tif !operatorsValid(numeratorOperators) || !operatorsValid(denominatorOperators) {\n\t\tlog.Println(\"[W] operators invalid\", item)\n\t\treturn\n\t}\n\n\thostnames, err := sdk.HostnamesByID(item.GroupId)\n\tif err != nil || len(hostnames) == 0 {\n\t\treturn\n\t}\n\n\tnow := time.Now().Unix()\n\n\tvalueMap, err := queryCounterLast(numeratorOperands, denominatorOperands, hostnames, now-int64(item.Step*2), now)\n\tif err != nil {\n\t\tlog.Println(\"[E]\", err, item)\n\t\treturn\n\t}\n\n\tvar numerator, denominator float64\n\tvar validCount int\n\n\tfor _, hostname := range hostnames {\n\t\tvar numeratorVal, denominatorVal float64\n\t\tvar err error\n\n\t\tif needComputeNumerator {\n\t\t\tnumeratorVal, err = compute(numeratorOperands, numeratorOperators, numeratorComputeMode, hostname, valueMap)\n\n\t\t\tif debug && err != nil {\n\t\t\t\tlog.Printf(\"[W] [hostname:%s] [numerator:%s] id:%d, err:%v\", hostname, item.Numerator, item.Id, err)\n\t\t\t} else if debug {\n\t\t\t\tlog.Printf(\"[D] [hostname:%s] [numerator:%s] id:%d, value:%0.4f\", hostname, item.Numerator, item.Id, numeratorVal)\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif needComputeDenominator {\n\t\t\tdenominatorVal, err = compute(denominatorOperands, denominatorOperators, denominatorComputeMode, hostname, valueMap)\n\n\t\t\tif debug && err != nil {\n\t\t\t\tlog.Printf(\"[W] [hostname:%s] [denominator:%s] id:%d, err:%v\", hostname, item.Denominator, item.Id, err)\n\t\t\t} else if debug {\n\t\t\t\tlog.Printf(\"[D] [hostname:%s] [denominator:%s] id:%d, value:%0.4f\", hostname, item.Denominator, item.Id, denominatorVal)\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif debug {\n\t\t\tlog.Printf(\"[D] hostname:%s  numerator:%0.4f  denominator:%0.4f  per:%0.4f\\n\", hostname, numeratorVal, denominatorVal, numeratorVal/denominatorVal)\n\t\t}\n\t\tnumerator += numeratorVal\n\t\tdenominator += denominatorVal\n\t\tvalidCount += 1\n\t}\n\n\tif !needComputeNumerator {\n\t\tif numeratorStr == \"$#\" {\n\t\t\tnumerator = float64(validCount)\n\t\t} else {\n\t\t\tnumerator, err = strconv.ParseFloat(numeratorStr, 64)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"[E] strconv.ParseFloat(%s) fail %v, id:%d\", numeratorStr, err, item.Id)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tif !needComputeDenominator {\n\t\tif denominatorStr == \"$#\" {\n\t\t\tdenominator = float64(validCount)\n\t\t} else {\n\t\t\tdenominator, err = strconv.ParseFloat(denominatorStr, 64)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"[E] strconv.ParseFloat(%s) fail %v, id:%d\", denominatorStr, err, item.Id)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tif denominator == 0 {\n\t\tlog.Println(\"[W] denominator == 0, id:\", item.Id)\n\t\treturn\n\t}\n\n\tif validCount == 0 {\n\t\tlog.Println(\"[W] validCount == 0, id:\", item.Id)\n\t\treturn\n\t}\n\n\tif debug {\n\t\tlog.Printf(\"[D] hostname:all  numerator:%0.4f  denominator:%0.4f  per:%0.4f\\n\", numerator, denominator, numerator/denominator)\n\t}\n\tsender.Push(item.Endpoint, item.Metric, item.Tags, numerator/denominator, item.DsType, int64(item.Step))\n}\n\nfunc parse(expression string, needCompute bool) (operands []string, operators []string, computeMode string) {\n\tif !needCompute {\n\t\treturn\n\t}\n\n\t// e.g. $(cpu.busy)\n\t// e.g. $(cpu.busy)+$(cpu.idle)-$(cpu.nice)\n\t// e.g. $(cpu.busy)>=80\n\t// e.g. ($(cpu.busy)+$(cpu.idle)-$(cpu.nice))>80\n\n\tsplitCounter, _ := regexp.Compile(`[\\$\\(\\)]+`)\n\titems := splitCounter.Split(expression, -1)\n\n\tcount := len(items)\n\tfor i, val := range items[1 : count-1] {\n\t\tif i%2 == 0 {\n\t\t\toperands = append(operands, val)\n\t\t} else {\n\t\t\toperators = append(operators, val)\n\t\t}\n\t}\n\tcomputeMode = items[count-1]\n\n\treturn\n}\n\nfunc cleanParam(val string) string {\n\tval = strings.TrimSpace(val)\n\tval = strings.Replace(val, \" \", \"\", -1)\n\tval = strings.Replace(val, \"\\r\", \"\", -1)\n\tval = strings.Replace(val, \"\\n\", \"\", -1)\n\tval = strings.Replace(val, \"\\t\", \"\", -1)\n\treturn val\n}\n\n// $#\n// 200\n// $(cpu.busy) + $(cpu.idle)\nfunc needCompute(val string) bool {\n\treturn strings.Contains(val, \"$(\")\n}\n\nfunc expressionValid(val string) bool {\n\t// use chinese character?\n\n\tif strings.Contains(val, \"（\") || strings.Contains(val, \"）\") {\n\t\treturn false\n\t}\n\n\tif val == \"$#\" {\n\t\treturn true\n\t}\n\n\t// e.g. $(cpu.busy)\n\t// e.g. $(cpu.busy)+$(cpu.idle)-$(cpu.nice)\n\tmatchMode0 := `^(\\$\\([^\\(\\)]+\\)[+-])*\\$\\([^\\(\\)]+\\)$`\n\tif ok, err := regexp.MatchString(matchMode0, val); err == nil && ok {\n\t\treturn true\n\t}\n\n\t// e.g. $(cpu.busy)>=80\n\tmatchMode1 := `^\\$\\([^\\(\\)]+\\)(>|=|<|>=|<=)\\d+(\\.\\d+)?$`\n\tif ok, err := regexp.MatchString(matchMode1, val); err == nil && ok {\n\t\treturn true\n\t}\n\n\t// e.g. ($(cpu.busy)+$(cpu.idle)-$(cpu.nice))>80\n\tmatchMode2 := `^\\((\\$\\([^\\(\\)]+\\)[+-])*\\$\\([^\\(\\)]+\\)\\)(>|=|<|>=|<=)\\d+(\\.\\d+)?$`\n\tif ok, err := regexp.MatchString(matchMode2, val); err == nil && ok {\n\t\treturn true\n\t}\n\n\t// e.g. 纯数字\n\tmatchMode3 := `^\\d+$`\n\tif ok, err := regexp.MatchString(matchMode3, val); err == nil && ok {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc operatorsValid(ops []string) bool {\n\tcount := len(ops)\n\tfor i := 0; i < count; i++ {\n\t\tif ops[i] != \"+\" && ops[i] != \"-\" {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "modules/aggregator/cron/run_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"testing\"\n)\n\nfunc Test_expressionValid(t *testing.T) {\n\n\texpressionMap := map[string]bool{\n\t\t// true\n\t\t\"1210\":                                true,\n\t\t\"$#\":                                  true,\n\t\t\"$(cpu.busy)\":                         true,\n\t\t\"$(cpu.busy)+$(cpu.idle)-$(cpu.nice)\": true,\n\t\t\"$(cpu.busy)>=80\":                     true,\n\t\t\"($(cpu.busy)+$(cpu.idle)-$(cpu.nice))>80\": true,\n\t\t\"$(qps/module=judge,project=falcon)\":       true,\n\t\t\"($(cpu.idle)+$(cpu.busy))=100\":            true,\n\n\t\t// false\n\t\t\"$((cpu.busy)\":                     false,\n\t\t\"$(cpu.idle)+$(cpu.busy)>40\":       false,\n\t\t\"($(cpu.idle)+$(cpu.busy)-60)>100\": false,\n\t}\n\n\tfor key, val := range expressionMap {\n\t\tif st := expressionValid(key); st != val {\n\t\t\tt.Errorf(\"func expressionValid() failure\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/aggregator/cron/updater.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/db\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n\t\"time\"\n)\n\nfunc UpdateItems() {\n\tfor {\n\t\tupdateItems()\n\t\td := time.Duration(g.Config().Database.Interval) * time.Second\n\t\ttime.Sleep(d)\n\t}\n}\n\nfunc updateItems() {\n\titems, err := db.ReadClusterMonitorItems()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tdeleteNoUseWorker(items)\n\tcreateWorkerIfNeed(items)\n}\n"
  },
  {
    "path": "modules/aggregator/cron/worker.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"log\"\n\t\"math/rand\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n)\n\ntype Worker struct {\n\tTicker      *time.Ticker\n\tClusterItem *g.Cluster\n\tQuit        chan struct{}\n}\n\nfunc NewWorker(ci *g.Cluster) Worker {\n\tw := Worker{}\n\tw.Quit = make(chan struct{})\n\tw.ClusterItem = ci\n\treturn w\n}\n\nfunc (this Worker) Start() {\n\tgo func() {\n\t\ts1 := rand.NewSource(time.Now().UnixNano() * this.ClusterItem.Id)\n\t\tr1 := rand.New(s1)\n\t\t// 60s, step usually\n\t\tdelay := r1.Int63n(60000)\n\t\tif g.Config().Debug {\n\t\t\tlog.Printf(\"[I] after %5d ms, start worker %d\", delay, this.ClusterItem.Id)\n\t\t}\n\n\t\ttime.Sleep(time.Duration(delay) * time.Millisecond)\n\t\tthis.Ticker = time.NewTicker(time.Duration(this.ClusterItem.Step) * time.Second)\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-this.Ticker.C:\n\t\t\t\tWorkerRun(this.ClusterItem)\n\t\t\tcase <-this.Quit:\n\t\t\t\tif g.Config().Debug {\n\t\t\t\t\tlog.Println(\"[I] drop worker\", this.ClusterItem)\n\t\t\t\t}\n\t\t\t\tthis.Ticker.Stop()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n}\n\nfunc (this Worker) Drop() {\n\tclose(this.Quit)\n}\n\nvar Workers = make(map[string]Worker)\n\nfunc deleteNoUseWorker(m map[string]*g.Cluster) {\n\tdel := []string{}\n\tfor key, worker := range Workers {\n\t\tif _, ok := m[key]; !ok {\n\t\t\tworker.Drop()\n\t\t\tdel = append(del, key)\n\t\t}\n\t}\n\n\tfor _, key := range del {\n\t\tdelete(Workers, key)\n\t}\n}\n\nfunc createWorkerIfNeed(m map[string]*g.Cluster) {\n\tfor key, item := range m {\n\t\tif _, ok := Workers[key]; !ok {\n\t\t\tif item.Step <= 0 {\n\t\t\t\tlog.Println(\"[W] invalid cluster(step <= 0):\", item)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tworker := NewWorker(item)\n\t\t\tWorkers[key] = worker\n\t\t\tworker.Start()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/aggregator/db/db.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"database/sql\"\n\t_ \"github.com/go-sql-driver/mysql\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n\t\"log\"\n)\n\nvar DB *sql.DB\n\nfunc Init() {\n\tvar err error\n\tDB, err = sql.Open(\"mysql\", g.Config().Database.Addr)\n\tif err != nil {\n\t\tlog.Fatalln(\"open db fail:\", err)\n\t}\n\n\tDB.SetMaxIdleConns(g.Config().Database.Idle)\n\n\terr = DB.Ping()\n\tif err != nil {\n\t\tlog.Fatalln(\"ping db fail:\", err)\n\t}\n}\n"
  },
  {
    "path": "modules/aggregator/db/reader.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n\t\"log\"\n)\n\nfunc ReadClusterMonitorItems() (M map[string]*g.Cluster, err error) {\n\tM = make(map[string]*g.Cluster)\n\tsql := \"SELECT `id`, `grp_id`, `numerator`, `denominator`, `endpoint`, `metric`, `tags`, `ds_type`, `step`, `last_update` FROM `cluster`\"\n\n\tcfg := g.Config()\n\tids := cfg.Database.Ids\n\tif len(ids) != 2 {\n\t\tlog.Fatalln(\"ids configuration error\")\n\t}\n\n\tif ids[0] != -1 && ids[1] != -1 {\n\t\tsql = fmt.Sprintf(\"%s WHERE `id` >= %d and `id` <= %d\", sql, ids[0], ids[1])\n\t} else {\n\t\tif ids[0] != -1 {\n\t\t\tsql = fmt.Sprintf(\"%s WHERE `id` >= %d\", sql, ids[0])\n\t\t}\n\n\t\tif ids[1] != -1 {\n\t\t\tsql = fmt.Sprintf(\"%s WHERE `id` <= %d\", sql, ids[1])\n\t\t}\n\t}\n\n\tif cfg.Debug {\n\t\tlog.Println(sql)\n\t}\n\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"[E]\", err)\n\t\treturn M, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar c g.Cluster\n\t\terr = rows.Scan(&c.Id, &c.GroupId, &c.Numerator, &c.Denominator, &c.Endpoint, &c.Metric, &c.Tags, &c.DsType, &c.Step, &c.LastUpdate)\n\t\tif err != nil {\n\t\t\tlog.Println(\"[E]\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tM[fmt.Sprintf(\"%d%v\", c.Id, c.LastUpdate)] = &c\n\t}\n\n\treturn M, err\n}\n"
  },
  {
    "path": "modules/aggregator/g/cfg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/toolkits/file\"\n\t\"log\"\n\t\"sync\"\n)\n\ntype HttpConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype DatabaseConfig struct {\n\tAddr     string `json:\"addr\"`\n\tIdle     int    `json:\"idle\"`\n\tIds      []int  `json:\"ids\"`\n\tInterval int64  `json:\"interval\"`\n}\n\ntype ApiConfig struct {\n\tConnectTimeout int32  `json:\"connect_timeout\"`\n\tRequestTimeout int32  `json:\"request_timeout\"`\n\tPlusApi        string `json:\"plus_api\"`\n\tPlusApiToken   string `json:\"plus_api_token\"`\n\tPushApi        string `json:\"push_api\"`\n}\n\ntype GlobalConfig struct {\n\tDebug    bool            `json:\"debug\"`\n\tHttp     *HttpConfig     `json:\"http\"`\n\tDatabase *DatabaseConfig `json:\"database\"`\n\tApi      *ApiConfig      `json:\"api\"`\n}\n\nvar (\n\tConfigFile string\n\tconfig     *GlobalConfig\n\tconfigLock = new(sync.RWMutex)\n)\n\nfunc Config() *GlobalConfig {\n\tconfigLock.RLock()\n\tdefer configLock.RUnlock()\n\treturn config\n}\n\nfunc ParseConfig(cfg string) {\n\tif cfg == \"\" {\n\t\tlog.Fatalln(\"use -c to specify configuration file\")\n\t}\n\n\tif !file.IsExist(cfg) {\n\t\tlog.Fatalln(\"config file:\", cfg, \"is not existent\")\n\t}\n\n\tConfigFile = cfg\n\n\tconfigContent, err := file.ToTrimString(cfg)\n\tif err != nil {\n\t\tlog.Fatalln(\"read config file:\", cfg, \"fail:\", err)\n\t}\n\n\tvar c GlobalConfig\n\terr = json.Unmarshal([]byte(configContent), &c)\n\tif err != nil {\n\t\tlog.Fatalln(\"parse config file:\", cfg, \"fail:\", err)\n\t}\n\n\tconfigLock.Lock()\n\tdefer configLock.Unlock()\n\tconfig = &c\n\tlog.Println(\"read config file:\", cfg, \"successfully\")\n}\n"
  },
  {
    "path": "modules/aggregator/g/g.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"runtime\"\n)\n\nvar (\n\tBinaryName string\n\tVersion    string\n\tGitCommit  string\n)\n\nfunc VersionMsg() string {\n\treturn Version + \"@\" + GitCommit\n}\n\nfunc init() {\n\truntime.GOMAXPROCS(runtime.NumCPU())\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)\n}\n"
  },
  {
    "path": "modules/aggregator/g/items.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype Cluster struct {\n\tId          int64\n\tGroupId     int64\n\tNumerator   string\n\tDenominator string\n\tEndpoint    string\n\tMetric      string\n\tTags        string\n\tDsType      string\n\tStep        int\n\tLastUpdate  time.Time\n}\n\nfunc (this *Cluster) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Id:%d, GroupId:%d, Numerator:%s, Denominator:%s, Endpoint:%s, Metric:%s, Tags:%s, DsType:%s, Step:%d, LastUpdate:%v>\",\n\t\tthis.Id,\n\t\tthis.GroupId,\n\t\tthis.Numerator,\n\t\tthis.Denominator,\n\t\tthis.Endpoint,\n\t\tthis.Metric,\n\t\tthis.Tags,\n\t\tthis.DsType,\n\t\tthis.Step,\n\t\tthis.LastUpdate,\n\t)\n}\n\n// key: Id+LastUpdate\ntype SafeClusterMonitorItems struct {\n\tsync.RWMutex\n\tM map[string]*Cluster\n}\n\nfunc NewClusterMonitorItems() *SafeClusterMonitorItems {\n\treturn &SafeClusterMonitorItems{M: make(map[string]*Cluster)}\n}\n\nfunc (this *SafeClusterMonitorItems) Init(m map[string]*Cluster) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n\nfunc (this *SafeClusterMonitorItems) Get() map[string]*Cluster {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.M\n}\n"
  },
  {
    "path": "modules/aggregator/http/common.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n\t\"github.com/toolkits/file\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc configCommonRoutes() {\n\thttp.HandleFunc(\"/health\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"ok\"))\n\t})\n\n\thttp.HandleFunc(\"/version\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(g.VersionMsg()))\n\t})\n\n\thttp.HandleFunc(\"/workdir\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, file.SelfDir())\n\t})\n\n\thttp.HandleFunc(\"/config/reload\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif strings.HasPrefix(r.RemoteAddr, \"127.0.0.1\") {\n\t\t\tg.ParseConfig(g.ConfigFile)\n\t\t\tRenderJson(w, g.Config())\n\t\t} else {\n\t\t\tw.Write([]byte(\"no privilege\"))\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "modules/aggregator/http/http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n\t\"log\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n)\n\ntype Dto struct {\n\tMsg  string      `json:\"msg\"`\n\tData interface{} `json:\"data\"`\n}\n\nfunc init() {\n\tconfigCommonRoutes()\n\tconfigProcRoutes()\n}\n\nfunc RenderJson(w http.ResponseWriter, v interface{}) {\n\tbs, err := json.Marshal(v)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\tw.Write(bs)\n}\n\nfunc RenderDataJson(w http.ResponseWriter, data interface{}) {\n\tRenderJson(w, Dto{Msg: \"success\", Data: data})\n}\n\nfunc RenderMsgJson(w http.ResponseWriter, msg string) {\n\tRenderJson(w, map[string]string{\"msg\": msg})\n}\n\nfunc AutoRender(w http.ResponseWriter, data interface{}, err error) {\n\tif err != nil {\n\t\tRenderMsgJson(w, err.Error())\n\t\treturn\n\t}\n\tRenderDataJson(w, data)\n}\n\nfunc Start() {\n\tif !g.Config().Http.Enabled {\n\t\treturn\n\t}\n\n\taddr := g.Config().Http.Listen\n\tif addr == \"\" {\n\t\treturn\n\t}\n\ts := &http.Server{\n\t\tAddr:           addr,\n\t\tMaxHeaderBytes: 1 << 30,\n\t}\n\tlog.Println(\"http listening\", addr)\n\tlog.Fatalln(s.ListenAndServe())\n}\n"
  },
  {
    "path": "modules/aggregator/http/proc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/db\"\n\t\"net/http\"\n)\n\nfunc configProcRoutes() {\n\thttp.HandleFunc(\"/items\", func(w http.ResponseWriter, r *http.Request) {\n\t\titems, err := db.ReadClusterMonitorItems()\n\t\tif err != nil {\n\t\t\tw.Write([]byte(err.Error()))\n\t\t\treturn\n\t\t}\n\n\t\tfor _, v := range items {\n\t\t\tw.Write([]byte(v.String()))\n\t\t\tw.Write([]byte(\"\\n\"))\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "modules/aggregator/main.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/open-falcon/falcon-plus/common/sdk/sender\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/cron\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/db\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/http\"\n)\n\nfunc main() {\n\tg.BinaryName = BinaryName\n\tg.Version = Version\n\tg.GitCommit = GitCommit\n\n\tcfg := flag.String(\"c\", \"cfg.json\", \"configuration file\")\n\tversion := flag.Bool(\"v\", false, \"show version\")\n\thelp := flag.Bool(\"h\", false, \"help\")\n\tflag.Parse()\n\n\tif *version {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\n\tif *help {\n\t\tflag.Usage()\n\t\tos.Exit(0)\n\t}\n\n\tg.ParseConfig(*cfg)\n\tdb.Init()\n\n\tgo http.Start()\n\tgo cron.UpdateItems()\n\n\t// sdk configuration\n\tsender.Debug = g.Config().Debug\n\tsender.PostPushUrl = g.Config().Api.PushApi\n\n\tsender.StartSender()\n\n\tsigs := make(chan os.Signal, 1)\n\tsignal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)\n\tgo func() {\n\t\t<-sigs\n\t\tfmt.Println()\n\t\tos.Exit(0)\n\t}()\n\n\tselect {}\n}\n"
  },
  {
    "path": "modules/aggregator/sdk/sdk.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sdk\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/common/sdk/requests\"\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n\tf \"github.com/open-falcon/falcon-plus/modules/api/app/model/falcon_portal\"\n\t\"github.com/toolkits/net/httplib\"\n\t\"time\"\n)\n\nfunc HostnamesByID(group_id int64) ([]string, error) {\n\n\turi := fmt.Sprintf(\"%s/api/v1/hostgroup/%d\", g.Config().Api.PlusApi, group_id)\n\treq, err := requests.CurlPlus(uri, \"GET\", \"aggregator\", g.Config().Api.PlusApiToken,\n\t\tmap[string]string{}, map[string]string{})\n\n\tif err != nil {\n\t\treturn []string{}, err\n\t}\n\n\ttype RESP struct {\n\t\tHostGroup f.HostGroup `json:\"hostgroup\"`\n\t\tHosts     []f.Host    `json:\"hosts\"`\n\t}\n\n\tresp := &RESP{}\n\terr = req.ToJson(&resp)\n\tif err != nil {\n\t\treturn []string{}, err\n\t}\n\n\thosts := []string{}\n\tnowTs := time.Now().Unix()\n\tfor _, x := range resp.Hosts {\n\t\tif x.MaintainBegin <= nowTs && nowTs <= x.MaintainEnd {\n\t\t\tcontinue\n\t\t}\n\t\thosts = append(hosts, x.Hostname)\n\t}\n\treturn hosts, nil\n}\n\nfunc QueryLastPoints(endpoints, counters []string) (resp []*cmodel.GraphLastResp, err error) {\n\tcfg := g.Config()\n\turi := fmt.Sprintf(\"%s/api/v1/graph/lastpoint\", cfg.Api.PlusApi)\n\n\tvar req *httplib.BeegoHttpRequest\n\theaders := map[string]string{\"Content-type\": \"application/json\"}\n\treq, err = requests.CurlPlus(uri, \"POST\", \"aggregator\", cfg.Api.PlusApiToken,\n\t\theaders, map[string]string{})\n\n\tif err != nil {\n\t\treturn\n\t}\n\n\treq.SetTimeout(time.Duration(cfg.Api.ConnectTimeout)*time.Millisecond,\n\t\ttime.Duration(cfg.Api.RequestTimeout)*time.Millisecond)\n\n\tbody := []*cmodel.GraphLastParam{}\n\tfor _, e := range endpoints {\n\t\tfor _, c := range counters {\n\t\t\tbody = append(body, &cmodel.GraphLastParam{e, c})\n\t\t}\n\t}\n\n\tb, err := json.Marshal(body)\n\tif err != nil {\n\t\treturn\n\t}\n\n\treq.Body(b)\n\n\terr = req.ToJson(&resp)\n\tif err != nil {\n\t\treturn\n\t}\n\n\treturn resp, nil\n}\n"
  },
  {
    "path": "modules/aggregator/sdk/sdk_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sdk\n\nimport (\n\t\"testing\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/aggregator/g\"\n\t. \"github.com/smartystreets/goconvey/convey\"\n)\n\nfunc init() {\n\tg.ParseConfig(\"../cfg.example.json\")\n}\n\nfunc TestSDK(t *testing.T) {\n\tConvey(\"get hostnames by id\", t, func() {\n\t\tr, err := HostnamesByID(1)\n\t\tt.Log(r, err)\n\t\tSo(err, ShouldBeNil)\n\t\tSo(len(r), ShouldBeGreaterThanOrEqualTo, 0)\n\t})\n\n\tConvey(\"query last points\", t, func() {\n\t\tr, err := QueryLastPoints([]string{\"laiweiofficemac\"}, []string{\"agent.alive\"})\n\t\tt.Log(r, err)\n\t\tSo(err, ShouldBeNil)\n\t\tSo(len(r), ShouldBeGreaterThanOrEqualTo, 0)\n\t\tfor _, x := range r {\n\t\t\tt.Log(x)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "modules/aggregator/version.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// build !release\npackage main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  },
  {
    "path": "modules/alarm/.gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n*.swp\n*.swo\n*.log\n.idea\n.DS_Store\n/var\n/falcon-alarm*\n/alarm*\n/cfg.json\n/gitignore\n\n"
  },
  {
    "path": "modules/alarm/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "modules/alarm/NOTICE",
    "content": "Open-Falcon\n\nCopyright (c) 2014-2015 Xiaomi, Inc. All Rights Reserved.\n\nThis product is licensed to you under the Apache License, Version 2.0 (the \"License\").\nYou may not use this product except in compliance with the License.\n\nThis product may include a number of subcomponents with separate copyright notices\nand license terms. Your use of these subcomponents is subject to the terms and\nconditions of the subcomponent's license, as noted in the LICENSE file.\n"
  },
  {
    "path": "modules/alarm/README.md",
    "content": "falcon-alarm\n============\n\njudge把报警event写入redis，alarm从redis读取event，做相应处理，可能是发报警短信、邮件，可能是callback某个http地址。\n\n\n## Installation\n\n```bash\n# set $GOPATH and $GOROOT\nmkdir -p $GOPATH/src/github.com/open-falcon\ncd $GOPATH/src/github.com/open-falcon\ngit clone https://github.com/open-falcon/falcon-plus/modules/alarm.git\ncd alarm\ngo get ./...\n./control build\n./control start\n```\n\n## Configuration\n\n- uicToken: 留空即可\n- http: 监听的http端口\n- redis: highQueues和lowQueues区别是是否做报警合并，默认配置是P0/P1不合并，收到之后直接发出；>=P2做报警合并\n- api: 其他各个组件的地址, 注意plus_api_token要和falcon-plus api组件配置文件中的default_token一致 \n- api im: 增加针对im的支持，如果采用wechat企业号，配置可参考 https://github.com/yanjunhui/chat\n\n"
  },
  {
    "path": "modules/alarm/api/links.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage api\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/toolkits/net/httplib\"\n\t\"time\"\n)\n\nfunc LinkToSMS(content string) (string, error) {\n\turi := fmt.Sprintf(\"%s/portal/links/store\", g.Config().Api.Dashboard)\n\treq := httplib.Post(uri).SetTimeout(3*time.Second, 10*time.Second)\n\treq.Body([]byte(content))\n\treturn req.String()\n}\n"
  },
  {
    "path": "modules/alarm/api/portal.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/toolkits/net/httplib\"\n\t\"sync\"\n\t\"time\"\n)\n\n//TODO:use api/app/model/falcon_portal/action.go\ntype Action struct {\n\tId                 int    `json:\"id\"`\n\tUic                string `json:\"uic\"`\n\tUrl                string `json:\"url\"`\n\tCallback           int    `json:\"callback\"`\n\tBeforeCallbackSms  int    `json:\"before_callback_sms\"`\n\tBeforeCallbackMail int    `json:\"before_callback_mail\"`\n\tAfterCallbackSms   int    `json:\"after_callback_sms\"`\n\tAfterCallbackMail  int    `json:\"after_callback_mail\"`\n}\n\ntype ActionCache struct {\n\tsync.RWMutex\n\tM map[int]*Action\n}\n\nvar Actions = &ActionCache{M: make(map[int]*Action)}\n\nfunc (this *ActionCache) Get(id int) *Action {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tval, exists := this.M[id]\n\tif !exists {\n\t\treturn nil\n\t}\n\n\treturn val\n}\n\nfunc (this *ActionCache) Set(id int, action *Action) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M[id] = action\n}\n\nfunc GetAction(id int) *Action {\n\taction := CurlAction(id)\n\n\tif action != nil {\n\t\tActions.Set(id, action)\n\t} else {\n\t\taction = Actions.Get(id)\n\t}\n\n\treturn action\n}\n\nfunc CurlAction(id int) *Action {\n\tif id <= 0 {\n\t\treturn nil\n\t}\n\n\turi := fmt.Sprintf(\"%s/api/v1/action/%d\", g.Config().Api.PlusApi, id)\n\treq := httplib.Get(uri).SetTimeout(5*time.Second, 30*time.Second)\n\ttoken, _ := json.Marshal(map[string]string{\n\t\t\"name\": \"falcon-alarm\",\n\t\t\"sig\":  g.Config().Api.PlusApiToken,\n\t})\n\treq.Header(\"Apitoken\", string(token))\n\n\tvar act Action\n\terr := req.ToJson(&act)\n\tif err != nil {\n\t\tlog.Errorf(\"curl %s fail: %v\", uri, err)\n\t\treturn nil\n\t}\n\n\treturn &act\n}\n"
  },
  {
    "path": "modules/alarm/api/portal_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage api\n\nimport (\n\t\"testing\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t. \"github.com/smartystreets/goconvey/convey\"\n)\n\nfunc init() {\n\tg.ParseConfig(\"../cfg.example.json\")\n}\n\nfunc TestPortalAPI(t *testing.T) {\n\tConvey(\"Get action from api failed\", t, func() {\n\t\tr := CurlAction(1)\n\t\tSo(r.Id, ShouldEqual, 1)\n\t})\n\n}\n"
  },
  {
    "path": "modules/alarm/api/uic.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/api/app/model/uic\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/toolkits/container/set\"\n\t\"github.com/toolkits/net/httplib\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype APIGetTeamOutput struct {\n\tuic.Team\n\tUsers       []*uic.User `json:\"users\"`\n\tTeamCreator string      `json:\"creator_name\"`\n}\n\ntype UsersCache struct {\n\tsync.RWMutex\n\tM map[string][]*uic.User\n}\n\nvar Users = &UsersCache{M: make(map[string][]*uic.User)}\n\nfunc (this *UsersCache) Get(team string) []*uic.User {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tval, exists := this.M[team]\n\tif !exists {\n\t\treturn nil\n\t}\n\n\treturn val\n}\n\nfunc (this *UsersCache) Set(team string, users []*uic.User) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M[team] = users\n}\n\nfunc UsersOf(team string) []*uic.User {\n\tusers := CurlUic(team)\n\n\tif users != nil {\n\t\tUsers.Set(team, users)\n\t} else {\n\t\tusers = Users.Get(team)\n\t}\n\n\treturn users\n}\n\nfunc GetUsers(teams string) map[string]*uic.User {\n\tuserMap := make(map[string]*uic.User)\n\tarr := strings.Split(teams, \",\")\n\tfor _, team := range arr {\n\t\tif team == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tusers := UsersOf(team)\n\t\tif users == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, user := range users {\n\t\t\tuserMap[user.Name] = user\n\t\t}\n\t}\n\treturn userMap\n}\n\n// return phones, emails, IM\nfunc ParseTeams(teams string) ([]string, []string, []string) {\n\tif teams == \"\" {\n\t\treturn []string{}, []string{}, []string{}\n\t}\n\n\tuserMap := GetUsers(teams)\n\tphoneSet := set.NewStringSet()\n\tmailSet := set.NewStringSet()\n\timSet := set.NewStringSet()\n\tfor _, user := range userMap {\n\t\tif user.Phone != \"\" {\n\t\t\tphoneSet.Add(user.Phone)\n\t\t}\n\t\tif user.Email != \"\" {\n\t\t\tmailSet.Add(user.Email)\n\t\t}\n\t\tif user.IM != \"\" {\n\t\t\timSet.Add(user.IM)\n\t\t}\n\t}\n\treturn phoneSet.ToSlice(), mailSet.ToSlice(), imSet.ToSlice()\n}\n\nfunc CurlUic(team string) []*uic.User {\n\tif team == \"\" {\n\t\treturn []*uic.User{}\n\t}\n\n\turi := fmt.Sprintf(\"%s/api/v1/team/name/%s\", g.Config().Api.PlusApi, team)\n\treq := httplib.Get(uri).SetTimeout(2*time.Second, 10*time.Second)\n\ttoken, _ := json.Marshal(map[string]string{\n\t\t\"name\": \"falcon-alarm\",\n\t\t\"sig\":  g.Config().Api.PlusApiToken,\n\t})\n\treq.Header(\"Apitoken\", string(token))\n\n\tvar team_users APIGetTeamOutput\n\terr := req.ToJson(&team_users)\n\tif err != nil {\n\t\tlog.Errorf(\"curl %s fail: %v\", uri, err)\n\t\treturn nil\n\t}\n\n\treturn team_users.Users\n}\n"
  },
  {
    "path": "modules/alarm/api/uic_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage api\n\nimport (\n\t\"testing\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\tlog \"github.com/sirupsen/logrus\"\n\t. \"github.com/smartystreets/goconvey/convey\"\n)\n\nfunc init() {\n\tlog.SetLevel(log.DebugLevel)\n\tg.ParseConfig(\"../cfg.example.json\")\n}\n\nfunc TestUicAPI(t *testing.T) {\n\tConvey(\"Get team users from api failed\", t, func() {\n\t\tr := CurlUic(\"plus-dev\")\n\t\tfor _, x := range r {\n\t\t\tlog.Debugf(\"%#v\", x)\n\t\t}\n\t\tSo(len(r), ShouldEqual, 1)\n\t})\n}\n"
  },
  {
    "path": "modules/alarm/cfg.example.json",
    "content": "{\n    \"log_level\": \"debug\",\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:9912\"\n    },\n    \"redis\": {\n        \"addr\": \"127.0.0.1:6379\",\n        \"maxIdle\": 5,\n        \"highQueues\": [\n            \"event:p0\",\n            \"event:p1\",\n            \"event:p2\"\n        ],\n        \"lowQueues\": [\n            \"event:p3\",\n            \"event:p4\",\n            \"event:p5\",\n            \"event:p6\"\n        ],\n        \"userIMQueue\": \"/queue/user/im\",\n        \"userSmsQueue\": \"/queue/user/sms\",\n        \"userMailQueue\": \"/queue/user/mail\"\n    },\n    \"api\": {\n        \"im\": \"http://127.0.0.1:10086/wechat\",\n        \"sms\": \"http://127.0.0.1:10086/sms\",\n        \"mail\": \"http://127.0.0.1:10086/mail\",\n        \"dashboard\": \"http://127.0.0.1:8081\",\n        \"plus_api\":\"http://127.0.0.1:8080\",\n        \"plus_api_token\": \"default-token-used-in-server-side\"\n    },\n    \"falcon_portal\": {\n        \"addr\": \"root:@tcp(127.0.0.1:3306)/alarms?charset=utf8&loc=Local\",\n        \"idle\": 10,\n        \"max\": 100\n    },\n    \"worker\": {\n        \"im\": 10,\n        \"sms\": 10,\n        \"mail\": 50\n    },\n    \"housekeeper\": {\n        \"event_retention_days\": 7,\n        \"event_delete_batch\": 100\n    }\n}\n"
  },
  {
    "path": "modules/alarm/control",
    "content": "#!/bin/bash\n\nWORKSPACE=$(cd $(dirname $0)/; pwd)\ncd $WORKSPACE\n\nmkdir -p var\n\nmodule=alarm\napp=falcon-$module\nconf=cfg.json\npidfile=var/app.pid\nlogfile=var/app.log\n\nfunction check_pid() {\n    if [ -f $pidfile ];then\n        pid=`cat $pidfile`\n        if [ -n $pid ]; then\n            running=`ps -p $pid|grep -v \"PID TTY\" |wc -l`\n            return $running\n        fi\n    fi\n    return 0\n}\n\nfunction start() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running already, pid=\"\n        cat $pidfile\n        return 1\n    fi\n\n    nohup ./$app -c $conf &> $logfile &\n    echo $! > $pidfile\n    echo \"$app started..., pid=$!\"\n}\n\nfunction stop() {\n    pid=`cat $pidfile`\n    kill $pid\n    echo \"$app stopped...\"\n}\n\nfunction restart() {\n    stop\n    sleep 1\n    start\n}\n\nfunction status() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running, pid=\"\n        cat $pidfile\n    else\n        echo \"$app is stopped\"\n    fi\n}\n\nfunction tailf() {\n    tail -f $logfile\n}\n\nfunction build() {\n    go build\n    if [ $? -ne 0 ]; then\n        exit $?\n    fi\n    mv $module $app\n    ./$app -v | grep -v \"config\"\n}\n\nfunction pack() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v|grep -v config`\n    file_list=\"control cfg.example.json $app\"\n    tar zcf $app-$version.tar.gz gitversion $file_list\n}\n\nfunction packbin() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v|grep -v config`\n    tar zcvf $app-bin-$version.tar.gz $app gitversion\n}\n\nfunction help() {\n    echo \"$0 build|pack|packbin|start|stop|restart|status|tail\"\n}\n\nif [ \"$1\" == \"\" ]; then\n    help\nelif [ \"$1\" == \"stop\" ];then\n    stop\nelif [ \"$1\" == \"start\" ];then\n    start\nelif [ \"$1\" == \"restart\" ];then\n    restart\nelif [ \"$1\" == \"status\" ];then\n    status\nelif [ \"$1\" == \"tail\" ];then\n    tailf\nelif [ \"$1\" == \"build\" ];then\n    build\nelif [ \"$1\" == \"pack\" ];then\n    pack\nelif [ \"$1\" == \"packbin\" ];then\n    packbin\nelse\n    help\nfi\n"
  },
  {
    "path": "modules/alarm/cron/builder.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n)\n\nfunc BuildCommonSMSContent(event *model.Event) string {\n\treturn fmt.Sprintf(\n\t\t\"[P%d][%s][%s][][%s %s %s %s %s%s%s][O%d %s]\",\n\t\tevent.Priority(),\n\t\tevent.Status,\n\t\tevent.Endpoint,\n\t\tevent.Note(),\n\t\tevent.Func(),\n\t\tevent.Metric(),\n\t\tutils.SortedTags(event.PushedTags),\n\t\tutils.ReadableFloat(event.LeftValue),\n\t\tevent.Operator(),\n\t\tutils.ReadableFloat(event.RightValue()),\n\t\tevent.CurrentStep,\n\t\tevent.FormattedTime(),\n\t)\n}\n\nfunc BuildCommonIMContent(event *model.Event) string {\n\treturn fmt.Sprintf(\n\t\t\"[P%d][%s][%s][][%s %s %s %s %s%s%s][O%d %s]\",\n\t\tevent.Priority(),\n\t\tevent.Status,\n\t\tevent.Endpoint,\n\t\tevent.Note(),\n\t\tevent.Func(),\n\t\tevent.Metric(),\n\t\tutils.SortedTags(event.PushedTags),\n\t\tutils.ReadableFloat(event.LeftValue),\n\t\tevent.Operator(),\n\t\tutils.ReadableFloat(event.RightValue()),\n\t\tevent.CurrentStep,\n\t\tevent.FormattedTime(),\n\t)\n}\n\nfunc BuildCommonMailContent(event *model.Event) string {\n\tlink := g.Link(event)\n\treturn fmt.Sprintf(\n\t\t\"%s\\r\\nP%d\\r\\nEndpoint:%s\\r\\nMetric:%s\\r\\nTags:%s\\r\\n%s: %s%s%s\\r\\nNote:%s\\r\\nMax:%d, Current:%d\\r\\nTimestamp:%s\\r\\n%s\\r\\n\",\n\t\tevent.Status,\n\t\tevent.Priority(),\n\t\tevent.Endpoint,\n\t\tevent.Metric(),\n\t\tutils.SortedTags(event.PushedTags),\n\t\tevent.Func(),\n\t\tutils.ReadableFloat(event.LeftValue),\n\t\tevent.Operator(),\n\t\tutils.ReadableFloat(event.RightValue()),\n\t\tevent.Note(),\n\t\tevent.MaxStep(),\n\t\tevent.CurrentStep,\n\t\tevent.FormattedTime(),\n\t\tlink,\n\t)\n}\n\nfunc GenerateSmsContent(event *model.Event) string {\n\treturn BuildCommonSMSContent(event)\n}\n\nfunc GenerateMailContent(event *model.Event) string {\n\treturn BuildCommonMailContent(event)\n}\n\nfunc GenerateIMContent(event *model.Event) string {\n\treturn BuildCommonIMContent(event)\n}\n"
  },
  {
    "path": "modules/alarm/cron/callback.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/api\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/redi\"\n\t\"github.com/toolkits/net/httplib\"\n)\n\nfunc HandleCallback(event *model.Event, action *api.Action) {\n\n\tteams := action.Uic\n\tphones := []string{}\n\tmails := []string{}\n\tims := []string{}\n\n\tif teams != \"\" {\n\t\tphones, mails, ims = api.ParseTeams(teams)\n\t\tsmsContent := GenerateSmsContent(event)\n\t\tmailContent := GenerateMailContent(event)\n\t\timContent := GenerateIMContent(event)\n\t\tif action.BeforeCallbackSms == 1 {\n\t\t\tredi.WriteSms(phones, smsContent)\n\t\t\tredi.WriteIM(ims, imContent)\n\t\t}\n\n\t\tif action.BeforeCallbackMail == 1 {\n\t\t\tredi.WriteMail(mails, smsContent, mailContent)\n\t\t}\n\t}\n\n\tmessage := Callback(event, action)\n\n\tif teams != \"\" {\n\t\tif action.AfterCallbackSms == 1 {\n\t\t\tredi.WriteSms(phones, message)\n\t\t\tredi.WriteIM(ims, message)\n\t\t}\n\n\t\tif action.AfterCallbackMail == 1 {\n\t\t\tredi.WriteMail(mails, message, message)\n\t\t}\n\t}\n\n}\n\nfunc Callback(event *model.Event, action *api.Action) string {\n\tif action.Url == \"\" {\n\t\treturn \"callback url is blank\"\n\t}\n\n\tL := make([]string, 0)\n\tif len(event.PushedTags) > 0 {\n\t\tfor k, v := range event.PushedTags {\n\t\t\tL = append(L, fmt.Sprintf(\"%s:%s\", k, v))\n\t\t}\n\t}\n\n\ttags := \"\"\n\tif len(L) > 0 {\n\t\ttags = strings.Join(L, \",\")\n\t}\n\n\treq := httplib.Get(action.Url).SetTimeout(3*time.Second, 20*time.Second)\n\n\treq.Param(\"endpoint\", event.Endpoint)\n\treq.Param(\"metric\", event.Metric())\n\treq.Param(\"status\", event.Status)\n\treq.Param(\"step\", fmt.Sprintf(\"%d\", event.CurrentStep))\n\treq.Param(\"priority\", fmt.Sprintf(\"%d\", event.Priority()))\n\treq.Param(\"time\", event.FormattedTime())\n\treq.Param(\"tpl_id\", fmt.Sprintf(\"%d\", event.TplId()))\n\treq.Param(\"exp_id\", fmt.Sprintf(\"%d\", event.ExpressionId()))\n\treq.Param(\"stra_id\", fmt.Sprintf(\"%d\", event.StrategyId()))\n\treq.Param(\"left_value\", utils.ReadableFloat(event.LeftValue))\n\treq.Param(\"tags\", tags)\n\n\tresp, e := req.String()\n\n\tsuccess := \"success\"\n\tif e != nil {\n\t\tlog.Errorf(\"callback fail, action:%v, event:%s, error:%s\", action, event.String(), e.Error())\n\t\tsuccess = fmt.Sprintf(\"fail:%s\", e.Error())\n\t}\n\tmessage := fmt.Sprintf(\"curl %s %s. resp: %s\", action.Url, success, resp)\n\tlog.Debugf(\"callback to url:%s, event:%s, resp:%s\", action.Url, event.String(), resp)\n\n\treturn message\n}\n"
  },
  {
    "path": "modules/alarm/cron/combiner.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/garyburd/redigo/redis\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/api\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/redi\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc CombineSms() {\n\tfor {\n\t\t// 每分钟读取处理一次\n\t\ttime.Sleep(time.Minute)\n\t\tcombineSms()\n\t}\n}\n\nfunc CombineMail() {\n\tfor {\n\t\t// 每分钟读取处理一次\n\t\ttime.Sleep(time.Minute)\n\t\tcombineMail()\n\t}\n}\n\nfunc CombineIM() {\n\tfor {\n\t\t// 每分钟读取处理一次\n\t\ttime.Sleep(time.Minute)\n\t\tcombineIM()\n\t}\n}\n\nfunc combineMail() {\n\tdtos := popAllMailDto()\n\tcount := len(dtos)\n\tif count == 0 {\n\t\treturn\n\t}\n\n\tdtoMap := make(map[string][]*MailDto)\n\tfor i := 0; i < count; i++ {\n\t\tkey := fmt.Sprintf(\"%d%s%s%s\", dtos[i].Priority, dtos[i].Status, dtos[i].Email, dtos[i].Metric)\n\t\tif _, ok := dtoMap[key]; ok {\n\t\t\tdtoMap[key] = append(dtoMap[key], dtos[i])\n\t\t} else {\n\t\t\tdtoMap[key] = []*MailDto{dtos[i]}\n\t\t}\n\t}\n\n\t// 不要在这处理，继续写回redis，否则重启alarm很容易丢数据\n\tfor _, arr := range dtoMap {\n\t\tsize := len(arr)\n\t\tif size == 1 {\n\t\t\tredi.WriteMail([]string{arr[0].Email}, arr[0].Subject, arr[0].Content)\n\t\t\tcontinue\n\t\t}\n\n\t\tsubject := fmt.Sprintf(\"[P%d][%s] %d %s\", arr[0].Priority, arr[0].Status, size, arr[0].Metric)\n\t\tcontentArr := make([]string, size)\n\t\tfor i := 0; i < size; i++ {\n\t\t\tcontentArr[i] = arr[i].Content\n\t\t}\n\t\tcontent := strings.Join(contentArr, \"\\r\\n\")\n\n\t\tlog.Debugf(\"combined mail subject:%s, content:%s\", subject, content)\n\t\tredi.WriteMail([]string{arr[0].Email}, subject, content)\n\t}\n}\n\nfunc combineIM() {\n\tdtos := popAllImDto()\n\tcount := len(dtos)\n\tif count == 0 {\n\t\treturn\n\t}\n\n\tdtoMap := make(map[string][]*ImDto)\n\tfor i := 0; i < count; i++ {\n\t\tkey := fmt.Sprintf(\"%d%s%s%s\", dtos[i].Priority, dtos[i].Status, dtos[i].IM, dtos[i].Metric)\n\t\tif _, ok := dtoMap[key]; ok {\n\t\t\tdtoMap[key] = append(dtoMap[key], dtos[i])\n\t\t} else {\n\t\t\tdtoMap[key] = []*ImDto{dtos[i]}\n\t\t}\n\t}\n\n\tfor _, arr := range dtoMap {\n\t\tsize := len(arr)\n\t\tif size == 1 {\n\t\t\tredi.WriteIM([]string{arr[0].IM}, arr[0].Content)\n\t\t\tcontinue\n\t\t}\n\n\t\t// 把多个im内容写入数据库，只给用户提供一个链接\n\t\tcontentArr := make([]string, size)\n\t\tfor i := 0; i < size; i++ {\n\t\t\tcontentArr[i] = arr[i].Content\n\t\t}\n\t\tcontent := strings.Join(contentArr, \",,\")\n\n\t\tfirst := arr[0].Content\n\t\tt := strings.Split(first, \"][\")\n\t\teg := \"\"\n\t\tif len(t) >= 3 {\n\t\t\teg = t[2]\n\t\t}\n\n\t\tpath, err := api.LinkToSMS(content)\n\t\tchat := \"\"\n\t\tif err != nil || path == \"\" {\n\t\t\tchat = fmt.Sprintf(\"[P%d][%s] %d %s.  e.g. %s. detail in email\", arr[0].Priority, arr[0].Status, size, arr[0].Metric, eg)\n\t\t\tlog.Error(\"create short link fail\", err)\n\t\t} else {\n\t\t\tchat = fmt.Sprintf(\"[P%d][%s] %d %s e.g. %s %s/portal/links/%s \",\n\t\t\t\tarr[0].Priority, arr[0].Status, size, arr[0].Metric, eg, g.Config().Api.Dashboard, path)\n\t\t\tlog.Debugf(\"combined im is:%s\", chat)\n\t\t}\n\n\t\tredi.WriteIM([]string{arr[0].IM}, chat)\n\t}\n}\n\nfunc combineSms() {\n\tdtos := popAllSmsDto()\n\tcount := len(dtos)\n\tif count == 0 {\n\t\treturn\n\t}\n\n\tdtoMap := make(map[string][]*SmsDto)\n\tfor i := 0; i < count; i++ {\n\t\tkey := fmt.Sprintf(\"%d%s%s%s\", dtos[i].Priority, dtos[i].Status, dtos[i].Phone, dtos[i].Metric)\n\t\tif _, ok := dtoMap[key]; ok {\n\t\t\tdtoMap[key] = append(dtoMap[key], dtos[i])\n\t\t} else {\n\t\t\tdtoMap[key] = []*SmsDto{dtos[i]}\n\t\t}\n\t}\n\n\tfor _, arr := range dtoMap {\n\t\tsize := len(arr)\n\t\tif size == 1 {\n\t\t\tredi.WriteSms([]string{arr[0].Phone}, arr[0].Content)\n\t\t\tcontinue\n\t\t}\n\n\t\t// 把多个sms内容写入数据库，只给用户提供一个链接\n\t\tcontentArr := make([]string, size)\n\t\tfor i := 0; i < size; i++ {\n\t\t\tcontentArr[i] = arr[i].Content\n\t\t}\n\t\tcontent := strings.Join(contentArr, \",,\")\n\n\t\tfirst := arr[0].Content\n\t\tt := strings.Split(first, \"][\")\n\t\teg := \"\"\n\t\tif len(t) >= 3 {\n\t\t\teg = t[2]\n\t\t}\n\n\t\tpath, err := api.LinkToSMS(content)\n\t\tsms := \"\"\n\t\tif err != nil || path == \"\" {\n\t\t\tsms = fmt.Sprintf(\"[P%d][%s] %d %s.  e.g. %s. detail in email\", arr[0].Priority, arr[0].Status, size, arr[0].Metric, eg)\n\t\t\tlog.Error(\"get short link fail\", err)\n\t\t} else {\n\t\t\tsms = fmt.Sprintf(\"[P%d][%s] %d %s e.g. %s %s/portal/links/%s \",\n\t\t\t\tarr[0].Priority, arr[0].Status, size, arr[0].Metric, eg, g.Config().Api.Dashboard, path)\n\t\t\tlog.Debugf(\"combined sms is:%s\", sms)\n\t\t}\n\n\t\tredi.WriteSms([]string{arr[0].Phone}, sms)\n\t}\n}\n\nfunc popAllSmsDto() []*SmsDto {\n\tret := []*SmsDto{}\n\tqueue := g.Config().Redis.UserSmsQueue\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\tfor {\n\t\treply, err := redis.String(rc.Do(\"RPOP\", queue))\n\t\tif err != nil {\n\t\t\tif err != redis.ErrNil {\n\t\t\t\tlog.Error(\"get SmsDto fail\", err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tif reply == \"\" || reply == \"nil\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar smsDto SmsDto\n\t\terr = json.Unmarshal([]byte(reply), &smsDto)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"json unmarshal SmsDto: %s fail: %v\", reply, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, &smsDto)\n\t}\n\n\treturn ret\n}\n\nfunc popAllMailDto() []*MailDto {\n\tret := []*MailDto{}\n\tqueue := g.Config().Redis.UserMailQueue\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\tfor {\n\t\treply, err := redis.String(rc.Do(\"RPOP\", queue))\n\t\tif err != nil {\n\t\t\tif err != redis.ErrNil {\n\t\t\t\tlog.Error(\"get MailDto fail\", err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tif reply == \"\" || reply == \"nil\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar mailDto MailDto\n\t\terr = json.Unmarshal([]byte(reply), &mailDto)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"json unmarshal MailDto: %s fail: %v\", reply, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, &mailDto)\n\t}\n\n\treturn ret\n}\n\nfunc popAllImDto() []*ImDto {\n\tret := []*ImDto{}\n\tqueue := g.Config().Redis.UserIMQueue\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\tfor {\n\t\treply, err := redis.String(rc.Do(\"RPOP\", queue))\n\t\tif err != nil {\n\t\t\tif err != redis.ErrNil {\n\t\t\t\tlog.Error(\"get ImDto fail\", err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tif reply == \"\" || reply == \"nil\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar imDto ImDto\n\t\terr = json.Unmarshal([]byte(reply), &imDto)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"json unmarshal imDto: %s fail: %v\", reply, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, &imDto)\n\t}\n\n\treturn ret\n}\n"
  },
  {
    "path": "modules/alarm/cron/event_cleaner.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\teventmodel \"github.com/open-falcon/falcon-plus/modules/alarm/model/event\"\n\t\"time\"\n)\n\nfunc CleanExpiredEvent() {\n\tfor {\n\n\t\tretention_days := g.Config().Housekeeper.EventRetentionDays\n\t\tdelete_batch := g.Config().Housekeeper.EventDeleteBatch\n\n\t\tnow := time.Now()\n\t\tbefore := now.Add(time.Duration(-retention_days*24) * time.Hour)\n\t\teventmodel.DeleteEventOlder(before, delete_batch)\n\n\t\ttime.Sleep(time.Second * 60)\n\t}\n}\n"
  },
  {
    "path": "modules/alarm/cron/event_consumer.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"encoding/json\"\n\tlog \"github.com/sirupsen/logrus\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/api\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/redi\"\n)\n\nfunc consume(event *cmodel.Event, isHigh bool) {\n\tactionId := event.ActionId()\n\tif actionId <= 0 {\n\t\treturn\n\t}\n\n\taction := api.GetAction(actionId)\n\tif action == nil {\n\t\treturn\n\t}\n\n\tif action.Callback == 1 {\n\t\tHandleCallback(event, action)\n\t}\n\n\tif isHigh {\n\t\tconsumeHighEvents(event, action)\n\t} else {\n\t\tconsumeLowEvents(event, action)\n\t}\n}\n\n// 高优先级的不做报警合并\nfunc consumeHighEvents(event *cmodel.Event, action *api.Action) {\n\tif action.Uic == \"\" {\n\t\treturn\n\t}\n\n\tphones, mails, ims := api.ParseTeams(action.Uic)\n\n\tsmsContent := GenerateSmsContent(event)\n\tmailContent := GenerateMailContent(event)\n\timContent := GenerateIMContent(event)\n\n\t// <=P2 才发送短信\n\tif event.Priority() < 3 {\n\t\tredi.WriteSms(phones, smsContent)\n\t}\n\n\tredi.WriteIM(ims, imContent)\n\tredi.WriteMail(mails, smsContent, mailContent)\n\n}\n\n// 低优先级的做报警合并\nfunc consumeLowEvents(event *cmodel.Event, action *api.Action) {\n\tif action.Uic == \"\" {\n\t\treturn\n\t}\n\n\t// <=P2 才发送短信\n\tif event.Priority() < 3 {\n\t\tParseUserSms(event, action)\n\t}\n\n\tParseUserIm(event, action)\n\tParseUserMail(event, action)\n}\n\nfunc ParseUserSms(event *cmodel.Event, action *api.Action) {\n\tuserMap := api.GetUsers(action.Uic)\n\n\tcontent := GenerateSmsContent(event)\n\tmetric := event.Metric()\n\tstatus := event.Status\n\tpriority := event.Priority()\n\n\tqueue := g.Config().Redis.UserSmsQueue\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\tfor _, user := range userMap {\n\t\tdto := SmsDto{\n\t\t\tPriority: priority,\n\t\t\tMetric:   metric,\n\t\t\tContent:  content,\n\t\t\tPhone:    user.Phone,\n\t\t\tStatus:   status,\n\t\t}\n\t\tbs, err := json.Marshal(dto)\n\t\tif err != nil {\n\t\t\tlog.Error(\"json marshal SmsDto fail:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\t_, err = rc.Do(\"LPUSH\", queue, string(bs))\n\t\tif err != nil {\n\t\t\tlog.Error(\"LPUSH redis\", queue, \"fail:\", err, \"dto:\", string(bs))\n\t\t}\n\t}\n}\n\nfunc ParseUserMail(event *cmodel.Event, action *api.Action) {\n\tuserMap := api.GetUsers(action.Uic)\n\n\tmetric := event.Metric()\n\tsubject := GenerateSmsContent(event)\n\tcontent := GenerateMailContent(event)\n\tstatus := event.Status\n\tpriority := event.Priority()\n\n\tqueue := g.Config().Redis.UserMailQueue\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\tfor _, user := range userMap {\n\t\tdto := MailDto{\n\t\t\tPriority: priority,\n\t\t\tMetric:   metric,\n\t\t\tSubject:  subject,\n\t\t\tContent:  content,\n\t\t\tEmail:    user.Email,\n\t\t\tStatus:   status,\n\t\t}\n\t\tbs, err := json.Marshal(dto)\n\t\tif err != nil {\n\t\t\tlog.Error(\"json marshal MailDto fail:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\t_, err = rc.Do(\"LPUSH\", queue, string(bs))\n\t\tif err != nil {\n\t\t\tlog.Error(\"LPUSH redis\", queue, \"fail:\", err, \"dto:\", string(bs))\n\t\t}\n\t}\n}\n\nfunc ParseUserIm(event *cmodel.Event, action *api.Action) {\n\tuserMap := api.GetUsers(action.Uic)\n\n\tcontent := GenerateIMContent(event)\n\tmetric := event.Metric()\n\tstatus := event.Status\n\tpriority := event.Priority()\n\n\tqueue := g.Config().Redis.UserIMQueue\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\tfor _, user := range userMap {\n\t\tdto := ImDto{\n\t\t\tPriority: priority,\n\t\t\tMetric:   metric,\n\t\t\tContent:  content,\n\t\t\tIM:       user.IM,\n\t\t\tStatus:   status,\n\t\t}\n\t\tbs, err := json.Marshal(dto)\n\t\tif err != nil {\n\t\t\tlog.Error(\"json marshal ImDto fail:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\t_, err = rc.Do(\"LPUSH\", queue, string(bs))\n\t\tif err != nil {\n\t\t\tlog.Error(\"LPUSH redis\", queue, \"fail:\", err, \"dto:\", string(bs))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/alarm/cron/event_reader.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"encoding/json\"\n\t\"time\"\n\n\t\"github.com/garyburd/redigo/redis\"\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\teventmodel \"github.com/open-falcon/falcon-plus/modules/alarm/model/event\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc ReadHighEvent() {\n\tqueues := g.Config().Redis.HighQueues\n\tif len(queues) == 0 {\n\t\treturn\n\t}\n\n\tfor {\n\t\tevent, err := popEvent(queues)\n\t\tif err != nil {\n\t\t\ttime.Sleep(time.Second)\n\t\t\tcontinue\n\t\t}\n\t\tconsume(event, true)\n\t}\n}\n\nfunc ReadLowEvent() {\n\tqueues := g.Config().Redis.LowQueues\n\tif len(queues) == 0 {\n\t\treturn\n\t}\n\n\tfor {\n\t\tevent, err := popEvent(queues)\n\t\tif err != nil {\n\t\t\ttime.Sleep(time.Second)\n\t\t\tcontinue\n\t\t}\n\t\tconsume(event, false)\n\t}\n}\n\nfunc popEvent(queues []string) (*cmodel.Event, error) {\n\n\tcount := len(queues)\n\n\tparams := make([]interface{}, count+1)\n\tfor i := 0; i < count; i++ {\n\t\tparams[i] = queues[i]\n\t}\n\t// set timeout 0\n\tparams[count] = 0\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\treply, err := redis.Strings(rc.Do(\"BRPOP\", params...))\n\tif err != nil {\n\t\tlog.Errorf(\"get alarm event from redis fail: %v\", err)\n\t\treturn nil, err\n\t}\n\n\tvar event cmodel.Event\n\terr = json.Unmarshal([]byte(reply[1]), &event)\n\tif err != nil {\n\t\tlog.Errorf(\"parse alarm event fail: %v\", err)\n\t\treturn nil, err\n\t}\n\n\tlog.Debugf(\"pop event: %s\", event.String())\n\n\t//insert event into database\n\teventmodel.InsertEvent(&event)\n\t// events no longer saved in memory\n\n\treturn &event, nil\n}\n"
  },
  {
    "path": "modules/alarm/cron/im_sender.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/redi\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/toolkits/net/httplib\"\n\t\"time\"\n)\n\nfunc ConsumeIM() {\n\tfor {\n\t\tL := redi.PopAllIM()\n\t\tif len(L) == 0 {\n\t\t\ttime.Sleep(time.Millisecond * 200)\n\t\t\tcontinue\n\t\t}\n\t\tSendIMList(L)\n\t}\n}\n\nfunc SendIMList(L []*model.IM) {\n\tfor _, im := range L {\n\t\tIMWorkerChan <- 1\n\t\tgo SendIM(im)\n\t}\n}\n\nfunc SendIM(im *model.IM) {\n\tdefer func() {\n\t\t<-IMWorkerChan\n\t}()\n\n\turl := g.Config().Api.IM\n\tr := httplib.Post(url).SetTimeout(5*time.Second, 30*time.Second)\n\tr.Param(\"tos\", im.Tos)\n\tr.Param(\"content\", im.Content)\n\tresp, err := r.String()\n\tif err != nil {\n\t\tlog.Errorf(\"send im fail, tos:%s, content:%s, error:%v\", im.Tos, im.Content, err)\n\t}\n\n\tlog.Debugf(\"send im:%v, resp:%v, url:%s\", im, resp, url)\n}\n"
  },
  {
    "path": "modules/alarm/cron/init_sender.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n)\n\nvar (\n\tIMWorkerChan   chan int\n\tSmsWorkerChan  chan int\n\tMailWorkerChan chan int\n)\n\nfunc InitSenderWorker() {\n\tworkerConfig := g.Config().Worker\n\tIMWorkerChan = make(chan int, workerConfig.IM)\n\tSmsWorkerChan = make(chan int, workerConfig.Sms)\n\tMailWorkerChan = make(chan int, workerConfig.Mail)\n}\n"
  },
  {
    "path": "modules/alarm/cron/mail_sender.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/redi\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/toolkits/net/httplib\"\n\t\"time\"\n)\n\nfunc ConsumeMail() {\n\tfor {\n\t\tL := redi.PopAllMail()\n\t\tif len(L) == 0 {\n\t\t\ttime.Sleep(time.Millisecond * 200)\n\t\t\tcontinue\n\t\t}\n\t\tSendMailList(L)\n\t}\n}\n\nfunc SendMailList(L []*model.Mail) {\n\tfor _, mail := range L {\n\t\tMailWorkerChan <- 1\n\t\tgo SendMail(mail)\n\t}\n}\n\nfunc SendMail(mail *model.Mail) {\n\tdefer func() {\n\t\t<-MailWorkerChan\n\t}()\n\n\turl := g.Config().Api.Mail\n\tr := httplib.Post(url).SetTimeout(5*time.Second, 30*time.Second)\n\tr.Param(\"tos\", mail.Tos)\n\tr.Param(\"subject\", mail.Subject)\n\tr.Param(\"content\", mail.Content)\n\tresp, err := r.String()\n\tif err != nil {\n\t\tlog.Errorf(\"send mail fail, receiver:%s, subject:%s, content:%s, error:%v\", mail.Tos, mail.Subject, mail.Content, err)\n\t}\n\n\tlog.Debugf(\"send mail:%v, resp:%v, url:%s\", mail, resp, url)\n}\n"
  },
  {
    "path": "modules/alarm/cron/model.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\ntype MailDto struct {\n\tPriority int    `json:\"priority\"`\n\tMetric   string `json:\"metric\"`\n\tSubject  string `json:\"subject\"`\n\tContent  string `json:\"content\"`\n\tEmail    string `json:\"email\"`\n\tStatus   string `json:\"status\"`\n}\n\ntype SmsDto struct {\n\tPriority int    `json:\"priority\"`\n\tMetric   string `json:\"metric\"`\n\tContent  string `json:\"content\"`\n\tPhone    string `json:\"phone\"`\n\tStatus   string `json:\"status\"`\n}\n\ntype ImDto struct {\n\tPriority int    `json:\"priority\"`\n\tMetric   string `json:\"metric\"`\n\tContent  string `json:\"content\"`\n\tIM       string `json:\"im\"`\n\tStatus   string `json:\"status\"`\n}\n"
  },
  {
    "path": "modules/alarm/cron/sms_sender.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/redi\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/toolkits/net/httplib\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc ConsumeSms() {\n\tfor {\n\t\tL := redi.PopAllSms()\n\t\tif len(L) == 0 {\n\t\t\ttime.Sleep(time.Millisecond * 200)\n\t\t\tcontinue\n\t\t}\n\t\tSendSmsList(L)\n\t}\n}\n\nfunc SendSmsList(L []*model.Sms) {\n\tfor _, sms := range L {\n\t\tSmsWorkerChan <- 1\n\t\tgo SendSms(sms)\n\t}\n}\n\nfunc SendSms(sms *model.Sms) {\n\tdefer func() {\n\t\t<-SmsWorkerChan\n\t}()\n\n\turl := g.Config().Api.Sms\n\tif !strings.HasPrefix(strings.ToLower(url), \"http\") {\n\t\tlog.Errorf(\"send sms fail, sms provider config is not valid\")\n\t\treturn\n\t}\n\tr := httplib.Post(url).SetTimeout(5*time.Second, 30*time.Second)\n\tr.Param(\"tos\", sms.Tos)\n\tr.Param(\"content\", sms.Content)\n\tresp, err := r.String()\n\tif err != nil {\n\t\tlog.Errorf(\"send sms fail, tos:%s, content:%s, error:%v\", sms.Tos, sms.Content, err)\n\t}\n\n\tlog.Debugf(\"send sms:%v, resp:%v, url:%s\", sms, resp, url)\n}\n"
  },
  {
    "path": "modules/alarm/g/cfg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"sync\"\n\n\t\"github.com/toolkits/file\"\n)\n\ntype HttpConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype RedisConfig struct {\n\tAddr          string   `json:\"addr\"`\n\tMaxIdle       int      `json:\"maxIdle\"`\n\tHighQueues    []string `json:\"highQueues\"`\n\tLowQueues     []string `json:\"lowQueues\"`\n\tUserIMQueue   string   `json:\"userIMQueue\"`\n\tUserSmsQueue  string   `json:\"userSmsQueue\"`\n\tUserMailQueue string   `json:\"userMailQueue\"`\n}\n\ntype ApiConfig struct {\n\tSms          string `json:\"sms\"`\n\tMail         string `json:\"mail\"`\n\tDashboard    string `json:\"dashboard\"`\n\tPlusApi      string `json:\"plus_api\"`\n\tPlusApiToken string `json:\"plus_api_token\"`\n\tIM           string `json:\"im\"`\n}\n\ntype FalconPortalConfig struct {\n\tAddr string `json:\"addr\"`\n\tIdle int    `json:\"idle\"`\n\tMax  int    `json:\"max\"`\n}\n\ntype WorkerConfig struct {\n\tIM   int `json:\"im\"`\n\tSms  int `json:\"sms\"`\n\tMail int `json:\"mail\"`\n}\n\ntype HousekeeperConfig struct {\n\tEventRetentionDays int `json:\"event_retention_days\"`\n\tEventDeleteBatch   int `json:\"event_delete_batch\"`\n}\n\ntype GlobalConfig struct {\n\tLogLevel     string              `json:\"log_level\"`\n\tFalconPortal *FalconPortalConfig `json:\"falcon_portal\"`\n\tHttp         *HttpConfig         `json:\"http\"`\n\tRedis        *RedisConfig        `json:\"redis\"`\n\tApi          *ApiConfig          `json:\"api\"`\n\tWorker       *WorkerConfig       `json:\"worker\"`\n\tHousekeeper  *HousekeeperConfig  `json:\"Housekeeper\"`\n}\n\nvar (\n\tConfigFile string\n\tconfig     *GlobalConfig\n\tconfigLock = new(sync.RWMutex)\n)\n\nfunc Config() *GlobalConfig {\n\tconfigLock.RLock()\n\tdefer configLock.RUnlock()\n\treturn config\n}\n\nfunc ParseConfig(cfg string) {\n\tif cfg == \"\" {\n\t\tlog.Fatalln(\"use -c to specify configuration file\")\n\t}\n\n\tif !file.IsExist(cfg) {\n\t\tlog.Fatalln(\"config file:\", cfg, \"is not existent\")\n\t}\n\n\tConfigFile = cfg\n\n\tconfigContent, err := file.ToTrimString(cfg)\n\tif err != nil {\n\t\tlog.Fatalln(\"read config file:\", cfg, \"fail:\", err)\n\t}\n\n\tvar c GlobalConfig\n\terr = json.Unmarshal([]byte(configContent), &c)\n\tif err != nil {\n\t\tlog.Fatalln(\"parse config file:\", cfg, \"fail:\", err)\n\t}\n\n\tconfigLock.Lock()\n\tdefer configLock.Unlock()\n\tconfig = &c\n\tlog.Println(\"read config file:\", cfg, \"successfully\")\n}\n"
  },
  {
    "path": "modules/alarm/g/eventdto.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"fmt\"\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n)\n\nfunc Link(event *cmodel.Event) string {\n\ttplId := event.TplId()\n\tif tplId != 0 {\n\t\treturn fmt.Sprintf(\"%s/portal/template/view/%d\", Config().Api.Dashboard, tplId)\n\t}\n\n\teid := event.ExpressionId()\n\tif eid != 0 {\n\t\treturn fmt.Sprintf(\"%s/portal/expression/view/%d\", Config().Api.Dashboard, eid)\n\t}\n\n\treturn \"\"\n}\n"
  },
  {
    "path": "modules/alarm/g/g.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"runtime\"\n)\n\nvar (\n\tBinaryName string\n\tVersion    string\n\tGitCommit  string\n)\n\nfunc VersionMsg() string {\n\treturn Version + \"@\" + GitCommit\n}\n\nfunc init() {\n\truntime.GOMAXPROCS(runtime.NumCPU())\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)\n}\n"
  },
  {
    "path": "modules/alarm/g/logger.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport log \"github.com/sirupsen/logrus\"\n\nfunc InitLog(level string) (err error) {\n\tswitch level {\n\tcase \"info\":\n\t\tlog.SetLevel(log.InfoLevel)\n\tcase \"debug\":\n\t\tlog.SetLevel(log.DebugLevel)\n\tcase \"warn\":\n\t\tlog.SetLevel(log.WarnLevel)\n\tdefault:\n\t\tlog.Fatal(\"log conf only allow [info, debug, warn], please check your confguire\")\n\t}\n\treturn\n}\n"
  },
  {
    "path": "modules/alarm/g/redis.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/garyburd/redigo/redis\"\n)\n\nvar RedisConnPool *redis.Pool\n\nfunc InitRedisConnPool() {\n\tredisConfig := Config().Redis\n\tauth, addr := formatRedisAddr(redisConfig.Addr)\n\tRedisConnPool = &redis.Pool{\n\t\tMaxIdle:     redisConfig.MaxIdle,\n\t\tIdleTimeout: 240 * time.Second,\n\t\tDial: func() (redis.Conn, error) {\n\t\t\tc, err := redis.Dial(\"tcp\", addr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif auth != \"\" {\n\t\t\t\tif _, err := c.Do(\"AUTH\", auth); err != nil {\n\t\t\t\t\t_ = c.Close()\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn c, err\n\t\t},\n\t\tTestOnBorrow: PingRedis,\n\t}\n}\n\nfunc formatRedisAddr(addrConfig string) (string, string) {\n\tif redisAddr := strings.Split(addrConfig, \"@\"); len(redisAddr) == 1 {\n\t\treturn \"\", redisAddr[0]\n\t} else {\n\t\treturn strings.Join(redisAddr[0:len(redisAddr)-1], \"@\"), redisAddr[len(redisAddr)-1]\n\t}\n}\n\nfunc PingRedis(c redis.Conn, t time.Time) error {\n\t_, err := c.Do(\"ping\")\n\tif err != nil {\n\t\tlog.Println(\"[ERROR] ping redis fail\", err)\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "modules/alarm/gitversion",
    "content": "30df6a7\n"
  },
  {
    "path": "modules/alarm/http/controller.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/toolkits/file\"\n)\n\nfunc Version(c *gin.Context) {\n\tc.String(200, g.VersionMsg())\n}\n\nfunc Health(c *gin.Context) {\n\tc.String(200, \"ok\")\n}\n\nfunc Workdir(c *gin.Context) {\n\tc.String(200, file.SelfDir())\n}\n"
  },
  {
    "path": "modules/alarm/http/http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"log\"\n)\n\nfunc Start() {\n\tif !g.Config().Http.Enabled {\n\t\treturn\n\t}\n\taddr := g.Config().Http.Listen\n\tif addr == \"\" {\n\t\treturn\n\t}\n\n\tr := gin.Default()\n\tr.GET(\"/version\", Version)\n\tr.GET(\"/health\", Health)\n\tr.GET(\"/workdir\", Workdir)\n\tr.Run(addr)\n\n\tlog.Println(\"http listening\", addr)\n}\n"
  },
  {
    "path": "modules/alarm/main.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/cron\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/http\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/model\"\n)\n\nfunc main() {\n\tg.BinaryName = BinaryName\n\tg.Version = Version\n\tg.GitCommit = GitCommit\n\n\tcfg := flag.String(\"c\", \"cfg.json\", \"configuration file\")\n\tversion := flag.Bool(\"v\", false, \"show version\")\n\thelp := flag.Bool(\"h\", false, \"help\")\n\tflag.Parse()\n\n\tif *version {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\n\tif *help {\n\t\tflag.Usage()\n\t\tos.Exit(0)\n\t}\n\n\tg.ParseConfig(*cfg)\n\n\tg.InitLog(g.Config().LogLevel)\n\tif g.Config().LogLevel != \"debug\" {\n\t\tgin.SetMode(gin.ReleaseMode)\n\t}\n\n\tg.InitRedisConnPool()\n\tmodel.InitDatabase()\n\tcron.InitSenderWorker()\n\n\tgo http.Start()\n\tgo cron.ReadHighEvent()\n\tgo cron.ReadLowEvent()\n\tgo cron.CombineSms()\n\tgo cron.CombineMail()\n\tgo cron.CombineIM()\n\tgo cron.ConsumeIM()\n\tgo cron.ConsumeSms()\n\tgo cron.ConsumeMail()\n\tgo cron.CleanExpiredEvent()\n\n\tsigs := make(chan os.Signal, 1)\n\tsignal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)\n\tgo func() {\n\t\t<-sigs\n\t\tfmt.Println()\n\t\tg.RedisConnPool.Close()\n\t\tos.Exit(0)\n\t}()\n\n\tselect {}\n}\n"
  },
  {
    "path": "modules/alarm/model/database.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"github.com/astaxie/beego/orm\"\n\t_ \"github.com/go-sql-driver/mysql\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/model/event\"\n)\n\nfunc InitDatabase() {\n\t// set default database\n\tconfig := g.Config()\n\torm.RegisterDataBase(\"default\", \"mysql\", config.FalconPortal.Addr, config.FalconPortal.Idle, config.FalconPortal.Max)\n\t// register model\n\torm.RegisterModel(new(event.Events), new(event.EventCases))\n\tif config.LogLevel == \"debug\" {\n\t\torm.Debug = true\n\t}\n}\n"
  },
  {
    "path": "modules/alarm/model/event/event.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage event\n\nimport (\n\t\"time\"\n)\n\ntype EventCases struct {\n\t// uniuq\n\tId       string `json:\"id\" orm:\"pk\"`\n\tEndpoint string `json:\"endpoint\"`\n\tMetric   string `json:\"metric\"`\n\tFunc     string `json:\"func\"`\n\t//leftValue + operator + rightValue\n\tCond          string    `json:\"cond\"`\n\tNote          string    `json:\"note\"`\n\tMaxStep       int       `json:\"max_step\"`\n\tCurrentStep   int       `json:\"current_step\"`\n\tPriority      int       `json:\"priority\"`\n\tStatus        string    `json:\"status\"`\n\tTimestamp     time.Time `json:\"start_at\"`\n\tUpdateAt      time.Time `json:\"update_at\"`\n\tProcessNote   int       `json:\"process_note\"`\n\tProcessStatus string    `json:\"process_status\"`\n\tTplCreator    string    `json:\"tpl_creator\"`\n\tExpressionId  int       `json:\"expression_id\"`\n\tStrategyId    int       `json:\"strategy_id\"`\n\tTemplateId    int       `json:\"template_id\"`\n\tEvents        []*Events `json:\"evevnts\" orm:\"reverse(many)\"`\n}\n\ntype Events struct {\n\tId          int         `json:\"id\" orm:\"pk\"`\n\tStep        int         `json:\"step\"`\n\tCond        string      `json:\"cond\"`\n\tStatus      int         `json:\"status\"`\n\tTimestamp   time.Time   `json:\"timestamp\"`\n\tEventCaseId *EventCases `json:\"event_caseId\" orm:\"rel(fk)\"`\n}\n"
  },
  {
    "path": "modules/alarm/model/event/event_operation.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage event\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"database/sql\"\n\n\t\"github.com/astaxie/beego/orm\"\n\tcoommonModel \"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst timeLayout = \"2006-01-02 15:04:05\"\n\nfunc insertEvent(q orm.Ormer, eve *coommonModel.Event) (res sql.Result, err error) {\n\tvar status int\n\tif status = 0; eve.Status == \"OK\" {\n\t\tstatus = 1\n\t}\n\tsqltemplete := `INSERT INTO events (\n\t\tevent_caseId,\n\t\tstep,\n\t\tcond,\n\t\tstatus,\n\t\ttimestamp\n\t) VALUES(?,?,?,?,?)`\n\tres, err = q.Raw(\n\t\tsqltemplete,\n\t\teve.Id,\n\t\teve.CurrentStep,\n\t\tfmt.Sprintf(\"%v %v %v\", eve.LeftValue, eve.Operator(), eve.RightValue()),\n\t\tstatus,\n\t\ttime.Unix(eve.EventTime, 0).Format(timeLayout),\n\t).Exec()\n\n\tif err != nil {\n\t\tlog.Errorf(\"insert event to db fail, error:%v\", err)\n\t} else {\n\t\tlastid, _ := res.LastInsertId()\n\t\tlog.Debug(\"insert event to db succ, last_insert_id:\", lastid)\n\t}\n\treturn\n}\n\nfunc InsertEvent(eve *coommonModel.Event) {\n\tq := orm.NewOrm()\n\tvar event []EventCases\n\tq.Raw(\"select * from event_cases where id = ?\", eve.Id).QueryRows(&event)\n\tvar sqlLog sql.Result\n\tvar errRes error\n\tlog.Debugf(\"events: %v\", eve)\n\tlog.Debugf(\"expression is null: %v\", eve.Expression == nil)\n\tif len(event) == 0 {\n\t\t//create cases\n\t\tsqltemplete := `INSERT INTO event_cases (\n\t\t\t\t\tid,\n\t\t\t\t\tendpoint,\n\t\t\t\t\tmetric,\n\t\t\t\t\tfunc,\n\t\t\t\t\tcond,\n\t\t\t\t\tnote,\n\t\t\t\t\tmax_step,\n\t\t\t\t\tcurrent_step,\n\t\t\t\t\tpriority,\n\t\t\t\t\tstatus,\n\t\t\t\t\ttimestamp,\n\t\t\t\t\tupdate_at,\n\t\t\t\t\ttpl_creator,\n\t\t\t\t\texpression_id,\n\t\t\t\t\tstrategy_id,\n\t\t\t\t\ttemplate_id\n\t\t\t\t\t) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`\n\n\t\ttpl_creator := \"\"\n\t\tif eve.Tpl() != nil {\n\t\t\ttpl_creator = eve.Tpl().Creator\n\t\t}\n\t\tsqlLog, errRes = q.Raw(\n\t\t\tsqltemplete,\n\t\t\teve.Id,\n\t\t\teve.Endpoint,\n\t\t\tcounterGen(eve.Metric(), utils.SortedTags(eve.PushedTags)),\n\t\t\teve.Func(),\n\t\t\t//cond\n\t\t\tfmt.Sprintf(\"%v %v %v\", eve.LeftValue, eve.Operator(), eve.RightValue()),\n\t\t\teve.Note(),\n\t\t\teve.MaxStep(),\n\t\t\teve.CurrentStep,\n\t\t\teve.Priority(),\n\t\t\teve.Status,\n\t\t\t//start_at\n\t\t\ttime.Unix(eve.EventTime, 0).Format(timeLayout),\n\t\t\t//update_at\n\t\t\ttime.Unix(eve.EventTime, 0).Format(timeLayout),\n\t\t\ttpl_creator,\n\t\t\teve.ExpressionId(),\n\t\t\teve.StrategyId(),\n\t\t\t//template_id\n\t\t\teve.TplId()).Exec()\n\n\t} else {\n\t\tsqltemplete := `UPDATE event_cases SET\n\t\t\t\tupdate_at = ?,\n\t\t\t\tmax_step = ?,\n\t\t\t\tcurrent_step = ?,\n\t\t\t\tnote = ?,\n\t\t\t\tcond = ?,\n\t\t\t\tstatus = ?,\n\t\t\t\tfunc = ?,\n\t\t\t\tpriority = ?,\n\t\t\t\ttpl_creator = ?,\n\t\t\t\texpression_id = ?,\n\t\t\t\tstrategy_id = ?,\n\t\t\t\ttemplate_id = ?`\n\t\t//reopen case\n\t\tif event[0].ProcessStatus == \"resolved\" || event[0].ProcessStatus == \"ignored\" {\n\t\t\tsqltemplete = fmt.Sprintf(\"%v ,process_status = '%s', process_note = %d\", sqltemplete, \"unresolved\", 0)\n\t\t}\n\n\t\ttpl_creator := \"\"\n\t\tif eve.Tpl() != nil {\n\t\t\ttpl_creator = eve.Tpl().Creator\n\t\t}\n\t\tif eve.CurrentStep == 1 {\n\t\t\t//update start time of cases\n\t\t\tsqltemplete = fmt.Sprintf(\"%v ,timestamp = ? WHERE id = ?\", sqltemplete)\n\t\t\tsqlLog, errRes = q.Raw(\n\t\t\t\tsqltemplete,\n\t\t\t\ttime.Unix(eve.EventTime, 0).Format(timeLayout),\n\t\t\t\teve.MaxStep(),\n\t\t\t\teve.CurrentStep,\n\t\t\t\teve.Note(),\n\t\t\t\tfmt.Sprintf(\"%v %v %v\", eve.LeftValue, eve.Operator(), eve.RightValue()),\n\t\t\t\teve.Status,\n\t\t\t\teve.Func(),\n\t\t\t\teve.Priority(),\n\t\t\t\ttpl_creator,\n\t\t\t\teve.ExpressionId(),\n\t\t\t\teve.StrategyId(),\n\t\t\t\teve.TplId(),\n\t\t\t\ttime.Unix(eve.EventTime, 0).Format(timeLayout),\n\t\t\t\teve.Id,\n\t\t\t).Exec()\n\t\t} else {\n\t\t\tsqltemplete = fmt.Sprintf(\"%v WHERE id = ?\", sqltemplete)\n\t\t\tsqlLog, errRes = q.Raw(\n\t\t\t\tsqltemplete,\n\t\t\t\ttime.Unix(eve.EventTime, 0).Format(timeLayout),\n\t\t\t\teve.MaxStep(),\n\t\t\t\teve.CurrentStep,\n\t\t\t\teve.Note(),\n\t\t\t\tfmt.Sprintf(\"%v %v %v\", eve.LeftValue, eve.Operator(), eve.RightValue()),\n\t\t\t\teve.Status,\n\t\t\t\teve.Func(),\n\t\t\t\teve.Priority(),\n\t\t\t\ttpl_creator,\n\t\t\t\teve.ExpressionId(),\n\t\t\t\teve.StrategyId(),\n\t\t\t\teve.TplId(),\n\t\t\t\teve.Id,\n\t\t\t).Exec()\n\t\t}\n\t}\n\tlog.Debug(fmt.Sprintf(\"%v, %v\", sqlLog, errRes))\n\t//insert case\n\tinsertEvent(q, eve)\n}\n\nfunc counterGen(metric string, tags string) (mycounter string) {\n\tmycounter = metric\n\tif tags != \"\" {\n\t\tmycounter = fmt.Sprintf(\"%s/%s\", metric, tags)\n\t}\n\treturn\n}\n\nfunc DeleteEventOlder(before time.Time, limit int) {\n\tt := before.Format(timeLayout)\n\tsqlTpl := `delete from events where timestamp<? limit ?`\n\tq := orm.NewOrm()\n\tresp, err := q.Raw(sqlTpl, t, limit).Exec()\n\tif err != nil {\n\t\tlog.Errorf(\"delete event older than %v fail, error:%v\", t, err)\n\t} else {\n\t\taffected, _ := resp.RowsAffected()\n\t\tlog.Debugf(\"delete event older than %v, rows affected:%v\", t, affected)\n\t}\n}\n"
  },
  {
    "path": "modules/alarm/model/im.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n)\n\ntype IM struct {\n\tTos     string `json:\"tos\"`\n\tContent string `json:\"content\"`\n}\n\nfunc (this *IM) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Tos:%s, Content:%s>\",\n\t\tthis.Tos,\n\t\tthis.Content,\n\t)\n}\n"
  },
  {
    "path": "modules/alarm/model/mail.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n)\n\ntype Mail struct {\n\tTos     string `json:\"tos\"`\n\tSubject string `json:\"subject\"`\n\tContent string `json:\"content\"`\n}\n\nfunc (this *Mail) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Tos:%s, Subject:%s, Content:%s>\",\n\t\tthis.Tos,\n\t\tthis.Subject,\n\t\tthis.Content,\n\t)\n}\n"
  },
  {
    "path": "modules/alarm/model/sms.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage model\n\nimport (\n\t\"fmt\"\n)\n\ntype Sms struct {\n\tTos     string `json:\"tos\"`\n\tContent string `json:\"content\"`\n}\n\nfunc (this *Sms) String() string {\n\treturn fmt.Sprintf(\n\t\t\"<Tos:%s, Content:%s>\",\n\t\tthis.Tos,\n\t\tthis.Content,\n\t)\n}\n"
  },
  {
    "path": "modules/alarm/redi/msg_reader.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage redi\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/garyburd/redigo/redis\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/model\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tIM_QUEUE_NAME   = \"/im\"\n\tSMS_QUEUE_NAME  = \"/sms\"\n\tMAIL_QUEUE_NAME = \"/mail\"\n)\n\nfunc PopAllSms() []*model.Sms {\n\tret := []*model.Sms{}\n\tqueue := SMS_QUEUE_NAME\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\tfor {\n\t\treply, err := redis.String(rc.Do(\"RPOP\", queue))\n\t\tif err != nil {\n\t\t\tif err != redis.ErrNil {\n\t\t\t\tlog.Error(err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tif reply == \"\" || reply == \"nil\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar sms model.Sms\n\t\terr = json.Unmarshal([]byte(reply), &sms)\n\t\tif err != nil {\n\t\t\tlog.Error(err, reply)\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, &sms)\n\t}\n\n\treturn ret\n}\n\nfunc PopAllIM() []*model.IM {\n\tret := []*model.IM{}\n\tqueue := IM_QUEUE_NAME\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\tfor {\n\t\treply, err := redis.String(rc.Do(\"RPOP\", queue))\n\t\tif err != nil {\n\t\t\tif err != redis.ErrNil {\n\t\t\t\tlog.Error(err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tif reply == \"\" || reply == \"nil\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar im model.IM\n\t\terr = json.Unmarshal([]byte(reply), &im)\n\t\tif err != nil {\n\t\t\tlog.Error(err, reply)\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, &im)\n\t}\n\n\treturn ret\n}\n\nfunc PopAllMail() []*model.Mail {\n\tret := []*model.Mail{}\n\tqueue := MAIL_QUEUE_NAME\n\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\n\tfor {\n\t\treply, err := redis.String(rc.Do(\"RPOP\", queue))\n\t\tif err != nil {\n\t\t\tif err != redis.ErrNil {\n\t\t\t\tlog.Error(err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tif reply == \"\" || reply == \"nil\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar mail model.Mail\n\t\terr = json.Unmarshal([]byte(reply), &mail)\n\t\tif err != nil {\n\t\t\tlog.Error(err, reply)\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, &mail)\n\t}\n\n\treturn ret\n}\n"
  },
  {
    "path": "modules/alarm/redi/msg_writer.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage redi\n\nimport (\n\t\"encoding/json\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"strings\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/alarm/model\"\n)\n\nfunc lpush(queue, message string) {\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\t_, err := rc.Do(\"LPUSH\", queue, message)\n\tif err != nil {\n\t\tlog.Error(\"LPUSH redis\", queue, \"fail:\", err, \"message:\", message)\n\t}\n}\n\nfunc WriteSmsModel(sms *model.Sms) {\n\tif sms == nil {\n\t\treturn\n\t}\n\n\tbs, err := json.Marshal(sms)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn\n\t}\n\n\tlog.Debugf(\"write sms to queue, sms:%v, queue:%s\", sms, SMS_QUEUE_NAME)\n\tlpush(SMS_QUEUE_NAME, string(bs))\n}\n\nfunc WriteIMModel(im *model.IM) {\n\tif im == nil {\n\t\treturn\n\t}\n\n\tbs, err := json.Marshal(im)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn\n\t}\n\n\tlog.Debugf(\"write im to queue, im:%v, queue:%s\", im, IM_QUEUE_NAME)\n\tlpush(IM_QUEUE_NAME, string(bs))\n}\n\nfunc WriteMailModel(mail *model.Mail) {\n\tif mail == nil {\n\t\treturn\n\t}\n\n\tbs, err := json.Marshal(mail)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn\n\t}\n\n\tlog.Debugf(\"write mail to queue, mail:%v, queue:%s\", mail, MAIL_QUEUE_NAME)\n\tlpush(MAIL_QUEUE_NAME, string(bs))\n}\n\nfunc WriteSms(tos []string, content string) {\n\tif len(tos) == 0 {\n\t\treturn\n\t}\n\n\tsms := &model.Sms{Tos: strings.Join(tos, \",\"), Content: content}\n\tWriteSmsModel(sms)\n}\n\nfunc WriteIM(tos []string, content string) {\n\tif len(tos) == 0 {\n\t\treturn\n\t}\n\n\tim := &model.IM{Tos: strings.Join(tos, \",\"), Content: content}\n\tWriteIMModel(im)\n}\n\nfunc WriteMail(tos []string, subject, content string) {\n\tif len(tos) == 0 {\n\t\treturn\n\t}\n\n\tmail := &model.Mail{Tos: strings.Join(tos, \",\"), Subject: subject, Content: content}\n\tWriteMailModel(mail)\n}\n"
  },
  {
    "path": "modules/alarm/version.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// build !release\npackage main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  },
  {
    "path": "modules/falcon2p8s/.gitignore",
    "content": "*.log\n.idea\n.DS_Store\n/var\n/falcon2p8s*\n/cfg.json\n/gitversion"
  },
  {
    "path": "modules/falcon2p8s/ReadMe.md",
    "content": "# falcon2p8s\n\n## 该组件是一个prometheus exporter，实现了将falcon监控数据转储到prometheus\n\n\n## 源码编译\n\n```bash\ncd $GOPATH/src/github.com/open-falcon\ngit clone https://github.com/open-falcon/falcon-plus.git\ncd falcon-plus/modules/falcon2p8s\ngo get \n./control build\n./control pack\n```\n\n最后一步会pack出一个tar.gz的安装包，拿着这个包去部署服务即可。\n\n## 服务部署\n服务部署，包括配置修改、启动服务、检验服务、停止服务等。这之前，需要将安装包解压到服务的部署目录下。\n\n```bash\n# 修改配置, 配置项含义见下文\nmv cfg.example.json cfg.json\nvim cfg.json\n\n# 启动服务\n./control start\n\n# 校验服务，看端口是否在监听\nss -tln\n\n# 检查log\n./control tail\n\n...\n# 停止服务\n./control stop\n\n```\n\n## 配置说明\n配置文件默认为./cfg.json。默认情况下，安装包会有一个cfg.example.json的配置文件示例。各配置项的含义，如下\n\n```bash\n## Configuration\n{\n    \"log_level\": \"debug\",\n    \"concurrent\": 100, # 处理metric的最大并发数\n\t\"http\": {\n\t\t\"listen\": \"0.0.0.0:9090\"\n\t},\n    \"rpc\": {\n        \"listen\": \"0.0.0.0:8080\"\n    }\n}\n```\n\nsm.example.yaml是使用prometheus operator中servicemonitor做服务发现时，对应的yaml，作为参考"
  },
  {
    "path": "modules/falcon2p8s/cfg.example.json",
    "content": "{\n    \"log_level\": \"debug\",\n    \"concurrent\": 100,\n\t\"http\": {\n\t\t\"listen\": \"0.0.0.0:9090\"\n\t},\n    \"rpc\": {\n        \"listen\": \"0.0.0.0:8080\"\n    }\n}"
  },
  {
    "path": "modules/falcon2p8s/control",
    "content": "#!/bin/bash\n\nWORKSPACE=$(cd $(dirname $0)/; pwd)\ncd $WORKSPACE\n\nmkdir -p var\n\nmodule=falcon2p8s\napp=falcon2p8s\nconf=cfg.json\npidfile=var/app.pid\nlogfile=var/app.log\n\nfunction check_pid() {\n    if [ -f $pidfile ];then\n        pid=`cat $pidfile`\n        if [ -n $pid ]; then\n            running=`ps -p $pid|grep -v \"PID TTY\" |wc -l`\n            return $running\n        fi\n    fi\n    return 0\n}\n\nfunction start() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running already, pid=\"\n        cat $pidfile\n        return 1\n    fi\n\n    nohup ./$app -c $conf >> $logfile 2>&1 &\n    echo $! > $pidfile\n    echo \"$app started..., pid=$!\"\n}\n\nfunction stop() {\n    pid=`cat $pidfile`\n    kill $pid\n    echo \"$app stopped...\"\n}\n\nfunction restart() {\n    stop\n    sleep 1\n    start\n}\n\nfunction status() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running, pid=\"\n        cat $pidfile\n    else\n        echo \"$app is stopped\"\n    fi\n}\n\nfunction tailf() {\n    tail -f $logfile\n}\n\nfunction build() {\n    go build\n    if [ $? -ne 0 ]; then\n        exit $?\n    fi\n    mv $module $app\n    ./$app -v\n}\n\nfunction pack() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-$version.tar.gz control cfg.example.json $app gitversion\n}\n\nfunction packbin() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-bin-$version.tar.gz $app gitversion\n}\n\nfunction help() {\n    echo \"$0 build|pack|packbin|start|stop|restart|status|tail\"\n}\n\nif [ \"$1\" == \"\" ]; then\n    help\nelif [ \"$1\" == \"stop\" ];then\n    stop\nelif [ \"$1\" == \"start\" ];then\n    start\nelif [ \"$1\" == \"restart\" ];then\n    restart\nelif [ \"$1\" == \"status\" ];then\n    status\nelif [ \"$1\" == \"tail\" ];then\n    tailf\nelif [ \"$1\" == \"build\" ];then\n    build\nelif [ \"$1\" == \"pack\" ];then\n    pack\nelif [ \"$1\" == \"packbin\" ];then\n    packbin\nelse\n    help\nfi\n"
  },
  {
    "path": "modules/falcon2p8s/g/cfg.go",
    "content": "package g\n\nimport (\n\t\"encoding/json\"\n\t\"sync\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/toolkits/file\"\n)\n\ntype HttpConfig struct {\n\tListen string `json:\"listen\"`\n}\n\ntype RpcConfig struct {\n\tListen string `json:\"listen\"`\n}\n\ntype GlobalConfig struct {\n\tLogLevel   string      `json:\"log_level\"`\n\tConcurrent int         `json:\"concurrent\"`\n\tHttp       *HttpConfig `json:\"http\"`\n\tRpc        *RpcConfig  `json:\"rpc\"`\n}\n\nvar (\n\tConfigFile string\n\tconfig     *GlobalConfig\n\tconfigLock = new(sync.RWMutex)\n)\n\nfunc Config() *GlobalConfig {\n\tconfigLock.RLock()\n\tdefer configLock.RUnlock()\n\treturn config\n}\n\nfunc ParseConfig(cfg string) {\n\tif cfg == \"\" {\n\t\tlog.Fatalln(\"use -c to specify configuration file\")\n\t}\n\n\tif !file.IsExist(cfg) {\n\t\tlog.Fatalln(\"config file:\", cfg, \"is not existent\")\n\t}\n\n\tConfigFile = cfg\n\n\tconfigContent, err := file.ToTrimString(cfg)\n\tif err != nil {\n\t\tlog.Fatalln(\"read config file:\", cfg, \"fail:\", err)\n\t}\n\n\tvar c GlobalConfig\n\terr = json.Unmarshal([]byte(configContent), &c)\n\tif err != nil {\n\t\tlog.Fatalln(\"parse config file:\", cfg, \"fail:\", err)\n\t}\n\n\tconfigLock.Lock()\n\tdefer configLock.Unlock()\n\tconfig = &c\n\tlog.Println(\"read config file:\", cfg, \"successfully\")\n}\n"
  },
  {
    "path": "modules/falcon2p8s/g/const.go",
    "content": "package g\n\nconst (\n\tGauge   = \"GAUGE\"\n\tCounter = \"COUNTER\"\n)\n"
  },
  {
    "path": "modules/falcon2p8s/g/g.go",
    "content": "package g\n\nvar (\n\tBinaryName string\n\tVersion    string\n\tGitCommit  string\n)\n\nfunc VersionMsg() string {\n\treturn Version + \"@\" + GitCommit\n}\n"
  },
  {
    "path": "modules/falcon2p8s/g/logger.go",
    "content": "package g\n\nimport log \"github.com/sirupsen/logrus\"\n\nfunc InitLog(level string) (err error) {\n\tswitch level {\n\tcase \"info\":\n\t\tlog.SetLevel(log.InfoLevel)\n\tcase \"debug\":\n\t\tlog.SetLevel(log.DebugLevel)\n\tcase \"warn\":\n\t\tlog.SetLevel(log.WarnLevel)\n\tdefault:\n\t\tlog.Fatal(\"log conf only allow [info, debug, warn], please check your confguire\")\n\t}\n\treturn\n}\n"
  },
  {
    "path": "modules/falcon2p8s/g/var.go",
    "content": "package g\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/oleiade/lane\"\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\nvar (\n\tIsScraping               bool\n\tP8sItemQueue             = lane.NewQueue()\n\tCollectorMap             sync.Map\n\tMetricTypeMap            sync.Map\n\tCounterCollectorValueMap sync.Map\n\tLastUpdateTimeOfCounter  sync.Map\n\tLastUpdateTimeOfGauge    sync.Map\n)\n\ntype LastUpdateTimeItem struct {\n\tLastUpdateTime time.Time\n\tPK             string\n\tTagValues      []string\n}\n\ntype UncheckedCollector struct {\n\tC          prometheus.Collector\n\tMetricType string\n}\n\nfunc (u UncheckedCollector) Describe(_ chan<- *prometheus.Desc) {}\nfunc (u UncheckedCollector) Collect(c chan<- prometheus.Metric) {\n\tu.C.Collect(c)\n}\n"
  },
  {
    "path": "modules/falcon2p8s/http/common.go",
    "content": "package http\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/g\"\n)\n\nfunc configCommonRoutes() {\n\trouter.GET(\"/version\", func(c *gin.Context) {\n\t\tJSONR(c, 200, gin.H{\"value\": g.VersionMsg()})\n\t})\n\n\trouter.GET(\"/health\", func(c *gin.Context) {\n\t\tc.String(200, \"ok\")\n\t})\n\n\trouter.POST(\"/config/reload\", func(c *gin.Context) {\n\t\tg.ParseConfig(g.ConfigFile)\n\t\tJSONR(c, 200, gin.H{\"msg\": \"ok\"})\n\t})\n}\n"
  },
  {
    "path": "modules/falcon2p8s/http/cron.go",
    "content": "package http\n\nimport (\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/g\"\n\t\"github.com/prometheus/client_golang/prometheus\"\n\t\"github.com/prometheus/client_golang/prometheus/promauto\"\n)\n\nvar queueSize = promauto.NewGauge(prometheus.GaugeOpts{\n\tName: \"falcon2p8s_relay_queue_size\",\n\tHelp: \"The size of falcon to prometheus relay server\",\n})\n\nfunc getqueueSize() {\n\tfor {\n\t\ttime.Sleep(time.Second * 30)\n\t\tqueueSize.Set(float64(g.P8sItemQueue.Size()))\n\t}\n}\n\nfunc cleanOutdatedGaugeMetrics() {\n\tfor {\n\t\ttime.Sleep(1 * time.Minute)\n\t\tg.LastUpdateTimeOfGauge.Range(func(key, value interface{}) bool {\n\t\t\tlastUpdateTimeItem := value.(g.LastUpdateTimeItem)\n\t\t\tif time.Since(lastUpdateTimeItem.LastUpdateTime) > 70*time.Second {\n\t\t\t\tif counter, ok := g.CollectorMap.Load(lastUpdateTimeItem.PK); ok {\n\t\t\t\t\tif uncheckedCollector, ok := counter.(g.UncheckedCollector); ok {\n\t\t\t\t\t\tuncheckedCollector.C.(*prometheus.GaugeVec).DeleteLabelValues(lastUpdateTimeItem.TagValues...)\n\t\t\t\t\t\tg.LastUpdateTimeOfGauge.Delete(key)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t}\n}\n\nfunc cleanOutdatedCounterMetrics() {\n\tfor {\n\t\ttime.Sleep(1 * time.Minute)\n\t\tg.LastUpdateTimeOfCounter.Range(func(key, value interface{}) bool {\n\t\t\tlastUpdateTimeItem := value.(g.LastUpdateTimeItem)\n\t\t\tif time.Since(lastUpdateTimeItem.LastUpdateTime) > 70*time.Second {\n\t\t\t\tif counter, ok := g.CollectorMap.Load(lastUpdateTimeItem.PK); ok {\n\t\t\t\t\tif uncheckedCollector, ok := counter.(g.UncheckedCollector); ok {\n\t\t\t\t\t\tuncheckedCollector.C.(*prometheus.CounterVec).DeleteLabelValues(lastUpdateTimeItem.TagValues...)\n\t\t\t\t\t\tg.LastUpdateTimeOfCounter.Delete(key)\n\t\t\t\t\t\tg.CounterCollectorValueMap.Delete(key)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "modules/falcon2p8s/http/helper.go",
    "content": "package http\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\ntype RespJson struct {\n\tError string `json:\"error,omitempty\"`\n\tMsg   string `json:\"message,omitempty\"`\n}\n\n// func JSONR(c *gin.Context, wcode int, msg interface{}) (werror error) {\nfunc JSONR(c *gin.Context, arg ...interface{}) (werror error) {\n\tvar (\n\t\twcode int\n\t\tmsg   interface{}\n\t)\n\n\tif len(arg) == 1 {\n\t\twcode = http.StatusOK\n\t\tmsg = arg[0]\n\t} else {\n\t\twcode = arg[0].(int)\n\t\tmsg = arg[1]\n\t}\n\n\tvar body interface{}\n\tif wcode == 200 {\n\t\tswitch msg.(type) {\n\t\tcase string:\n\t\t\tbody = RespJson{Msg: msg.(string)}\n\t\t\tc.JSON(http.StatusOK, body)\n\t\tdefault:\n\t\t\tc.JSON(http.StatusOK, msg)\n\t\t\tbody = msg\n\t\t}\n\t} else {\n\t\tswitch msg.(type) {\n\t\tcase string:\n\t\t\tbody = RespJson{Error: msg.(string)}\n\t\t\tc.JSON(wcode, body)\n\t\tcase error:\n\t\t\tbody = RespJson{Error: msg.(error).Error()}\n\t\t\tc.JSON(wcode, body)\n\t\tdefault:\n\t\t\tbody = RespJson{Error: \"system type error. please ask admin for help\"}\n\t\t\tc.JSON(wcode, body)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "modules/falcon2p8s/http/http.go",
    "content": "package http\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/middlewares\"\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/rpc\"\n\t\"github.com/prometheus/client_golang/prometheus\"\n\t\"github.com/prometheus/client_golang/prometheus/promhttp\"\n\tlog \"github.com/sirupsen/logrus\"\n\tnsema \"github.com/toolkits/concurrent/semaphore\"\n)\n\nvar router *gin.Engine\n\nfunc RenderJson(w http.ResponseWriter, v interface{}) {\n\tbs, err := json.Marshal(v)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\tw.Write(bs)\n}\n\nvar counterMutex, gaugeMutex sync.Mutex\n\nfunc dealGaugeMetric(p8sItem *rpc.P8sItem) {\n\tcounter, ok := g.CollectorMap.Load(p8sItem.PK)\n\t// 启动之后首次接收到该指标\n\tif !ok {\n\t\tgaugeMutex.Lock()\n\t\tgaugeVec := prometheus.NewGaugeVec(\n\t\t\tprometheus.GaugeOpts{\n\t\t\t\tName: p8sItem.Metric,\n\t\t\t}, p8sItem.TagKeys)\n\t\tuncheckedCollector := g.UncheckedCollector{C: gaugeVec, MetricType: p8sItem.MetricType}\n\t\tcounter, ok = g.CollectorMap.Load(p8sItem.PK)\n\t\tif !ok {\n\t\t\tif err := prometheus.Register(uncheckedCollector); err != nil {\n\t\t\t\tlog.Errorf(\"Error Register gauge. %s\", err.Error())\n\t\t\t} else {\n\t\t\t\tgv, err := gaugeVec.GetMetricWithLabelValues(p8sItem.TagValues...)\n\t\t\t\tif err == nil {\n\t\t\t\t\tgv.Set(p8sItem.Value)\n\t\t\t\t\tg.CollectorMap.Store(p8sItem.PK, uncheckedCollector)\n\t\t\t\t} else {\n\t\t\t\t\tlog.Errorf(\"Error when GetMetricWithLabelValues first time. item: %v, err: %s\\n\", *p8sItem, err.Error())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tgaugeMutex.Unlock()\n\t}\n\t// exporter启动之后非首次接收到该指标\n\tif counter != nil {\n\t\tuncheckedCollector, ok := counter.(g.UncheckedCollector)\n\t\tif ok {\n\t\t\tuncheckedCollector.C.(*prometheus.GaugeVec).WithLabelValues(p8sItem.TagValues...).Set(p8sItem.Value)\n\t\t} else {\n\t\t\tlog.Errorf(\"Error assert to UncheckedCollector. item: %v\", p8sItem)\n\t\t}\n\t}\n\t// 记录当前指标存储的时间\n\tg.LastUpdateTimeOfGauge.Store(p8sItem.PKWithTagValue, g.LastUpdateTimeItem{\n\t\tLastUpdateTime: time.Now(),\n\t\tPK:             p8sItem.PK,\n\t\tTagValues:      p8sItem.TagValues,\n\t})\n}\n\nfunc dealCounterMetric(p8sItem *rpc.P8sItem) {\n\tcounter, ok := g.CollectorMap.Load(p8sItem.PK)\n\t// exporter启动之后首次接收到该指标\n\tif !ok {\n\t\tcounterMutex.Lock()\n\t\tcounterVec := prometheus.NewCounterVec(\n\t\t\tprometheus.CounterOpts{\n\t\t\t\tName: p8sItem.Metric,\n\t\t\t}, p8sItem.TagKeys)\n\t\tuncheckedCollector := g.UncheckedCollector{C: counterVec, MetricType: p8sItem.MetricType}\n\t\tcounter, ok = g.CollectorMap.Load(p8sItem.PK)\n\t\tif !ok {\n\t\t\tif err := prometheus.Register(uncheckedCollector); err != nil {\n\t\t\t\tlog.Errorf(\"Error Register counter. %s\", err.Error())\n\t\t\t} else {\n\t\t\t\tc, err := counterVec.GetMetricWithLabelValues(p8sItem.TagValues...)\n\t\t\t\tif err == nil {\n\t\t\t\t\tif p8sItem.Value >= 0 {\n\t\t\t\t\t\tc.Add(p8sItem.Value)\n\t\t\t\t\t\tg.CollectorMap.Store(p8sItem.PK, uncheckedCollector)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlog.Errorf(\"Error counter value less than zero: %v\\n\", *p8sItem)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlog.Errorf(\"Error when GetMetricWithLabelValues first time. item: %v, err: %s\\n\", *p8sItem, err.Error())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcounterMutex.Unlock()\n\t}\n\t// exporter启动之后非首次接收到该指标\n\tif counter != nil {\n\t\tuncheckedCollector, ok := counter.(g.UncheckedCollector)\n\t\tif ok {\n\t\t\t// counter类型需要add相较上一次值的增量\n\t\t\tlastValue, ok := g.CounterCollectorValueMap.Load(p8sItem.PKWithTagValue)\n\t\t\tif ok {\n\t\t\t\tlv, ok := lastValue.(float64)\n\t\t\t\tif ok {\n\t\t\t\t\tif p8sItem.Value-lv >= 0 {\n\t\t\t\t\t\tuncheckedCollector.C.(*prometheus.CounterVec).WithLabelValues(p8sItem.TagValues...).Add(p8sItem.Value - lv)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlog.Errorf(\"Error counter value cannot decrease. current value %f, last value: %f. item: %v\\n\", p8sItem.Value, lv, *p8sItem)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlog.Errorf(\"Error assert last value: %v\\n\", *p8sItem)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif p8sItem.Value >= 0 {\n\t\t\t\t\tuncheckedCollector.C.(*prometheus.CounterVec).WithLabelValues(p8sItem.TagValues...).Add(p8sItem.Value)\n\t\t\t\t} else {\n\t\t\t\t\tlog.Errorf(\"Error counter value less than zero: %v\\n\", *p8sItem)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Errorf(\"Error assert to UncheckedCollector. item: %v\", p8sItem)\n\t\t}\n\t}\n\tg.CounterCollectorValueMap.Store(p8sItem.PKWithTagValue, p8sItem.Value)\n\t// 记录当前指标存储的时间\n\tg.LastUpdateTimeOfCounter.Store(p8sItem.PKWithTagValue, g.LastUpdateTimeItem{\n\t\tLastUpdateTime: time.Now(),\n\t\tPK:             p8sItem.PK,\n\t\tTagValues:      p8sItem.TagValues,\n\t})\n}\n\nfunc Start() {\n\tgo func() {\n\t\tconcurrent := g.Config().Concurrent\n\t\tif concurrent == 0 {\n\t\t\tconcurrent = 100\n\t\t}\n\t\tsema := nsema.NewSemaphore(concurrent)\n\t\tfor {\n\t\t\tsema.Acquire()\n\t\t\t// 如果prometheus开始抓取数据，就延迟一分钟之后再更新collector中的数据\n\t\t\t// 避免同一指标上一分钟的监控数据被覆盖，导致点位缺失\n\t\t\tif g.IsScraping {\n\t\t\t\ttime.Sleep(time.Millisecond * 1)\n\t\t\t\tsema.Release()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\titem := g.P8sItemQueue.Shift()\n\t\t\tgo func() {\n\t\t\t\tdefer sema.Release()\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tlog.Errorf(\"Exception is recover. %#v\", r)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tif item == nil {\n\t\t\t\t\ttime.Sleep(time.Millisecond * 1)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tp8sItem, ok := item.(*rpc.P8sItem)\n\t\t\t\tif !ok {\n\t\t\t\t\tlog.Errorf(\"Error when assert item to p8sItem. %#v\", item)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// 检测是否存在相同metric，但type不同的监控项\n\t\t\t\tmetricType, ok := g.MetricTypeMap.Load(p8sItem.Metric)\n\t\t\t\tif ok {\n\t\t\t\t\tif p8sItem.MetricType != metricType {\n\t\t\t\t\t\tlog.Errorf(\"Error metric same, but metric type not coincide. item: %v\\n\", *p8sItem)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tg.MetricTypeMap.Store(p8sItem.Metric, p8sItem.MetricType)\n\t\t\t\t}\n\n\t\t\t\tif p8sItem.MetricType == g.Counter {\n\t\t\t\t\tdealCounterMetric(p8sItem)\n\t\t\t\t} else {\n\t\t\t\t\tdealGaugeMetric(p8sItem)\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}()\n\n\tgo getqueueSize()\n\n\tgo cleanOutdatedGaugeMetrics()\n\tgo cleanOutdatedCounterMetrics()\n\n\trouter = gin.Default()\n\n\tconfigCommonRoutes()\n\n\tif g.Config().LogLevel != \"debug\" {\n\t\tgin.SetMode(gin.ReleaseMode)\n\t}\n\trouter.Use(middlewares.CheckIsScraping())\n\trouter.GET(\"/metrics\", prometheusHandler())\n\n\taddr := g.Config().Http.Listen\n\tif addr == \"\" {\n\t\taddr = \"0.0.0.0:9090\"\n\t}\n\tlog.Println(\"http listening\", addr)\n\tif err := router.Run(addr); err != nil {\n\t\tlog.Fatal(\"Error gin run: \", err.Error())\n\t\treturn\n\t}\n}\n\nfunc prometheusHandler() gin.HandlerFunc {\n\th := promhttp.Handler()\n\treturn func(c *gin.Context) {\n\t\th.ServeHTTP(c.Writer, c.Request)\n\t}\n}\n"
  },
  {
    "path": "modules/falcon2p8s/main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/http\"\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/rpc\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc startSignal(pid int) {\n\tsigs := make(chan os.Signal, 1)\n\tlog.Println(pid, \"register signal notify\")\n\tsignal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)\n\n\tfor {\n\t\ts := <-sigs\n\t\tlog.Println(\"recv\", s)\n\t\tswitch s {\n\t\tcase syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:\n\t\t\tfor {\n\t\t\t\tif g.P8sItemQueue.Empty() {\n\t\t\t\t\tlog.Println(\"graceful shut down\")\n\t\t\t\t\tlog.Println(pid, \"exit\")\n\t\t\t\t\tos.Exit(0)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc main() {\n\tg.BinaryName = BinaryName\n\tg.Version = Version\n\tg.GitCommit = GitCommit\n\n\tcfg := flag.String(\"c\", \"cfg.json\", \"configuration file\")\n\tversion := flag.Bool(\"v\", false, \"show version\")\n\thelp := flag.Bool(\"h\", false, \"help\")\n\tflag.Parse()\n\n\tif *version {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\n\tif *help {\n\t\tflag.Usage()\n\t\tos.Exit(0)\n\t}\n\n\tg.ParseConfig(*cfg)\n\n\tg.InitLog(g.Config().LogLevel)\n\n\tgo rpc.Start()\n\tgo http.Start()\n\tstartSignal(os.Getpid())\n}\n"
  },
  {
    "path": "modules/falcon2p8s/middlewares/scraping.go",
    "content": "package middlewares\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/g\"\n)\n\nfunc CheckIsScraping() gin.HandlerFunc {\n\treturn func(c *gin.Context) {\n\t\tg.IsScraping = true\n\t\tc.Next()\n\t\tg.IsScraping = false\n\t}\n}\n"
  },
  {
    "path": "modules/falcon2p8s/rpc/model.go",
    "content": "package rpc\n\n// code == 0 => success\n// code == 1 => bad request\ntype SimpleRpcResponse struct {\n\tCode int `json:\"code\"`\n}\n\ntype NullRpcRequest struct {\n}\n\ntype P8sItem struct {\n\tEndpoint       string            `json:\"endpoint\"`\n\tMetric         string            `json:\"metric\"`\n\tTags           map[string]string `json:\"tags\"`\n\tTagKeys        []string          `json:\"-\"`\n\tTagValues      []string          `json:\"-\"`\n\tValue          float64           `json:\"value\"`\n\tTimestamp      int64             `json:\"timestamp\"`\n\tMetricType     string            `json:\"metric_type\"`\n\tStep           int               `json:\"step\"`\n\tPK             string            `json:\"-\"`\n\tPKWithTagValue string            `json:\"-\"`\n}\n"
  },
  {
    "path": "modules/falcon2p8s/rpc/receiver.go",
    "content": "package rpc\n\nimport (\n\t\"regexp\"\n\t\"sync\"\n\t\"unicode\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/utils\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst MetricNameChars = \"[^a-zA-Z0-9_:]\"\nconst TagKeyNameChars = \"[^a-zA-Z0-9_]\"\n\nvar metricNameRegexp, tagKeyNameCharsRegexp *regexp.Regexp\n\nfunc init() {\n\tmetricNameRegexp, _ = regexp.Compile(MetricNameChars)\n\ttagKeyNameCharsRegexp, _ = regexp.Compile(TagKeyNameChars)\n}\n\ntype P8sRelay int\n\nfunc (this *P8sRelay) Ping(req NullRpcRequest, resp *SimpleRpcResponse) error {\n\treturn nil\n}\n\n// Metric转换规范：[^a-zA-Z0-9_:] 会被替换为下划线，数字开头会添加 F_ 前缀\n// Tag key转换规范：[^a-zA-Z0-9_] 会被替换为下划线，数字开头会添加 F_ 前缀\nfunc (this *P8sRelay) Send(items []*P8sItem, resp *SimpleRpcResponse) error {\n\twg := sync.WaitGroup{}\n\tfor _, item := range items {\n\t\twg.Add(1)\n\t\tgo func(item *P8sItem) {\n\t\t\tdefer wg.Done()\n\t\t\tif item.MetricType == g.Counter && item.Value < 0 {\n\t\t\t\tlog.Printf(\"Error counter value is less than zero. %v\\n\", *item)\n\t\t\t\treturn\n\t\t\t}\n\t\t\titem.Metric = metricNameRegexp.ReplaceAllString(item.Metric, \"_\")\n\t\t\tif unicode.IsDigit(rune(item.Metric[0])) {\n\t\t\t\titem.Metric = \"F_\" + item.Metric\n\t\t\t}\n\t\t\titem.Tags[\"hostname\"] = item.Endpoint\n\t\t\tfor key, value := range item.Tags {\n\t\t\t\tdelete(item.Tags, key)\n\t\t\t\tkey = tagKeyNameCharsRegexp.ReplaceAllString(key, \"_\")\n\t\t\t\tif unicode.IsDigit(rune(key[0])) {\n\t\t\t\t\tkey = \"F_\" + key\n\t\t\t\t}\n\t\t\t\titem.Tags[key] = value\n\t\t\t}\n\t\t\titem.TagKeys, item.TagValues = utils.SortedTagKVs(item.Tags)\n\t\t\titem.PK = utils.PK(item.Metric, item.TagKeys)\n\t\t\titem.PKWithTagValue = utils.PKWithTagValue(item.Metric, item.Tags)\n\t\t\tg.P8sItemQueue.Append(item)\n\t\t}(item)\n\t}\n\twg.Wait()\n\treturn nil\n}\n"
  },
  {
    "path": "modules/falcon2p8s/rpc/rpc.go",
    "content": "package rpc\n\nimport (\n\t\"net\"\n\t\"net/rpc\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/falcon2p8s/g\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc Start() {\n\taddr := g.Config().Rpc.Listen\n\tif addr == \"\" {\n\t\taddr = \"0.0.0.0:8080\"\n\t}\n\ttcpAddr, err := net.ResolveTCPAddr(\"tcp\", addr)\n\tif err != nil {\n\t\tlog.Fatalf(\"net.ResolveTCPAddr fail: %s\", err)\n\t}\n\n\tlistener, err := net.ListenTCP(\"tcp\", tcpAddr)\n\tif err != nil {\n\t\tlog.Fatalf(\"listen %s fail: %s\", addr, err)\n\t} else {\n\t\tlog.Println(\"rpc listening\", addr)\n\t}\n\n\trpc.Register(new(P8sRelay))\n\n\tfor {\n\t\tconn, err := listener.Accept()\n\t\tif err != nil {\n\t\t\tlog.Printf(\"listener.Accept occur error: %s\", err)\n\t\t\tcontinue\n\t\t}\n\t\tgo rpc.ServeConn(conn)\n\t}\n}\n"
  },
  {
    "path": "modules/falcon2p8s/sm.example.yaml",
    "content": "#  如果使用prometheus operator中的servicemonitor来做服务发现，下面yaml可供参考\napiVersion: monitoring.coreos.com/v1\nkind: ServiceMonitor\nmetadata:\n  labels:\n    app: falcon2p8s-exporter\n  name: falcon2p8s-exporter\n  namespace: monitoring\nspec:\n  endpoints:\n  - interval: 61s\n    path: /metrics\n    port: tcp-9090-9090\n    relabelings:\n    - action: replace\n      regex: .*\n      replacement: falcon2p8s\n      sourceLabels:\n      - __address__\n      targetLabel: instance\n    - action: labeldrop\n      regex: endpoint|namespace|service\n    scheme: http\n    scrapeTimeout: 20s\n  namespaceSelector:\n    matchNames:\n    - monitoring\n  selector:\n    matchLabels:\n      app: falcon2p8s-exporter\n\n---\n\napiVersion: v1\nkind: Service\nmetadata:\n  labels:\n    app: falcon2p8s-exporter\n  name: falcon2p8s-exporter\n  namespace: monitoring\nspec:\n  ports:\n  - name: tcp-9090-9090\n    port: 9090\n    protocol: TCP\n    targetPort: 9090\n  type: ClusterIP\n\n--- \n\napiVersion: v1\nkind: Endpoints\nmetadata:\n  labels:\n    app: falcon2p8s-exporter\n  name: falcon2p8s-exporter\n  namespace: monitoring\nsubsets:\n- addresses:\n  - ip: 192.168.1.1\n  - ip: 192.168.1.2\n  ports:\n  - name: tcp-9090-9090\n    port: 9090\n    protocol: TCP"
  },
  {
    "path": "modules/falcon2p8s/utils/func.go",
    "content": "package utils\n\nimport (\n\t\"bytes\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n)\n\nvar bufferPool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}\n\nfunc SortedTags(tags map[string]string) string {\n\tif tags == nil {\n\t\treturn \"\"\n\t}\n\tsize := len(tags)\n\tif size == 0 {\n\t\treturn \"\"\n\t}\n\tret := bufferPool.Get().(*bytes.Buffer)\n\tret.Reset()\n\tdefer bufferPool.Put(ret)\n\n\tif size == 1 {\n\t\tfor k, v := range tags {\n\t\t\tret.WriteString(k)\n\t\t\tret.WriteString(\"=\")\n\t\t\tret.WriteString(v)\n\t\t}\n\t\treturn ret.String()\n\t}\n\n\tkeys := make([]string, size)\n\ti := 0\n\tfor k := range tags {\n\t\tkeys[i] = k\n\t\ti++\n\t}\n\n\tsort.Strings(keys)\n\n\tfor j, key := range keys {\n\t\tret.WriteString(key)\n\t\tret.WriteString(\"=\")\n\t\tret.WriteString(tags[key])\n\t\tif j != size-1 {\n\t\t\tret.WriteString(\",\")\n\t\t}\n\t}\n\n\treturn ret.String()\n}\n\nfunc PK(metric string, tagkeys []string) string {\n\tret := bufferPool.Get().(*bytes.Buffer)\n\tret.Reset()\n\tdefer bufferPool.Put(ret)\n\tif len(tagkeys) == 0 {\n\t\tret.WriteString(metric)\n\t\treturn ret.String()\n\t}\n\tret.WriteString(metric)\n\tret.WriteString(\"/\")\n\tret.WriteString(strings.Join(tagkeys, \",\"))\n\treturn ret.String()\n}\n\nfunc PKWithTagValue(metric string, tags map[string]string) string {\n\tret := bufferPool.Get().(*bytes.Buffer)\n\tret.Reset()\n\tdefer bufferPool.Put(ret)\n\n\tif len(tags) == 0 {\n\t\tret.WriteString(metric)\n\t\treturn ret.String()\n\t}\n\tret.WriteString(metric)\n\tret.WriteString(\"/\")\n\tret.WriteString(SortedTags(tags))\n\treturn ret.String()\n}\n\nfunc SortedTagKVs(tags map[string]string) (tagKeys, tagValues []string) {\n\tif tags == nil {\n\t\treturn\n\t}\n\tsize := len(tags)\n\tif size == 0 {\n\t\treturn\n\t}\n\tif size == 1 {\n\t\tfor k, v := range tags {\n\t\t\ttagKeys = append(tagKeys, k)\n\t\t\ttagValues = append(tagValues, v)\n\t\t}\n\t\treturn\n\t}\n\tkeys := make([]string, size)\n\ti := 0\n\tfor k := range tags {\n\t\tkeys[i] = k\n\t\ti++\n\t}\n\tsort.Strings(keys)\n\tfor _, key := range keys {\n\t\ttagKeys = append(tagKeys, key)\n\t\ttagValues = append(tagValues, tags[key])\n\t}\n\treturn\n}\n"
  },
  {
    "path": "modules/falcon2p8s/version.go",
    "content": "package main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  },
  {
    "path": "modules/gateway/README.md",
    "content": "## Introduction\n\n多IDC时，可能面对 \"分区到中心的专线网络质量较差&公网ACL不通\" 等问题。这时，可以在分区内部署一套数据路由服务，接收本分区内的所有流量(包括所有的agent流量)，然后通过公网(开通ACL)，将数据push给中心的Transfer。如下图，\n![gateway.png](https://raw.githubusercontent.com/niean/niean.github.io/master/images/20150806/gateway.png)\n\n站在client端的角度，gateway和transfer提供了完全一致的功能和接口。**只有遇到网络分区的情况时，才有必要使用gateway组件**。\n\n### Build\n\n请参考[falcon-plus README](https://github.com/open-falcon/falcon-plus)\n\n### Deploy\n服务部署，包括配置修改、启动服务、检验服务、停止服务等。这之前，需要将安装包解压到服务的部署目录下。\n\n```\n# modify config\nmv cfg.example.json cfg.json\nvim cfg.json\n\n# start service\n./open-falcon start gateway\n\n# check, you should get 'ok'\n./open-falcon monitor gateway\n\n...\n# stop service\n./open-falcon stop gateway\n\n```\n服务启动后，可以通过日志查看服务的运行状态，日志文件地址为./var/app.log。可以通过调试脚本./test/debug查看服务器的内部状态数据，如 运行 bash ./test/debug 可以得到服务器内部状态的统计信息。\n\ngateway组件，部署于分区中。单个gateway实例的转发能力，为 {1核, 500MB内存, Qps不小于1W/s}；但我们仍然建议，一个分区至少部署两个gateway实例，来实现高可用。\n\n## Configuration\n\n\n```\n{\n    \"debug\": true,\n    \"minStep\": 30,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:16060\"\n    },\n    \"rpc\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:18433\"\n    },\n    \"socket\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:14444\",\n        \"timeout\": 3600\n    },\n    \"judge\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"cluster\": {\n            \"judge-00\" : \"%%JUDGE_RPC%%\"\n        }\n    },\n    \"graph\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"cluster\": {\n            \"graph-00\" : \"%%GRAPH_RPC%%\"\n        }\n    },\n   \"tsdb\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"retry\": 3,\n        \"address\": \"127.0.0.1:8088\"\n    },\n    \"transfer\": {\n        \"enabled\": true,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"retry\": 3,\n        \"cluster\": {\n            \"t1\": \"%%TRANSFER_RPC%%\"\n        }\n    }\n```\n\n从版本**v0.0.11**后，gateway组件引入了golang业务监控组件[GoPerfcounter](https://github.com/niean/goperfcounter)。GoPerfcounter会主动将gateway的内部状态数据，push给本地的falcon-agent，其配置文件`perfcounter.json`内容如下，含义见[这里](https://github.com/niean/goperfcounter/blob/master/README.md#配置)\n\n```\n{\n    \"tags\": \"service=gateway\", // 业务监控数据的标签\n    \"bases\": [\"debug\",\"runtime\"], // 开启gvm基础信息采集\n    \"push\": { // 开启主动推送,数据将被推送至本机的falcon-agent\n        \"enabled\": true\n    },\n    \"http\": { // 开启http调试，并复用gateway的http端口\n        \"enabled\": true\n    }\n}\n```\n\n## Debug\n可以通过调试脚本./test/debug查看服务器的内部状态数据，含义如下\n\n```\n# bash ./test/debug\n{\n    \"data\": {\n        \"gauge\": {\n            \"SendQueueSize\": { // size of cached items\n                \"value\": 0\n            }\n        },\n        \"meter\": {\n            \"Recv\": { // counter of items received\n                \"rate\": 954.88407253945127,\n                \"rate.15min\": 938.12973764674587,\n                \"rate.1min\": 892.82060496256759,\n                \"rate.5min\": 889.51059449035426,\n                \"sum\": 2460636\n            },\n            \"Send\": { // counter of items sent to transfer\n                \"rate\": 950.21411950079619,\n                \"rate.15min\": 918.55392627259835,\n                \"rate.1min\": 886.32981239416608,\n                \"rate.5min\": 888.16132862191205,\n                \"sum\": 2458708\n            },\n            \"SendFail\": { // counter of items sent to transfer failed\n                \"rate\": 0,\n                \"rate.15min\": 0,\n                \"rate.1min\": 0,\n                \"rate.5min\": 0,\n                \"sum\": 0\n            },  \n            \"SendDrop\": { // counter of items sent to transfer drop\n                \"rate\": 0,\n                \"rate.15min\": 0,\n                \"rate.1min\": 0,\n                \"rate.5min\": 0,\n                \"sum\": 0\n            },    \n        }\n    },\n    \"msg\": \"success\"\n}\n```\n\n## TODO\n+ 加密gateway经过公网传输的数据\n"
  },
  {
    "path": "modules/graph/.gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n.test\n\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n*.swp\n*.swo\n*.log\n*.temp\n\n.idea\n.DS_Store\n/var\n/graph\n/falcon-graph*\n/cfg.json\n/test/*.go\n/test/build\n\ntmp\ncfg.json\ngitversion\n"
  },
  {
    "path": "modules/graph/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "modules/graph/NOTICE",
    "content": "Open-Falcon\n\nCopyright (c) 2014-2015 Xiaomi, Inc. All Rights Reserved.\n\nThis product is licensed to you under the Apache License, Version 2.0 (the \"License\").\nYou may not use this product except in compliance with the License.\n\nThis product may include a number of subcomponents with separate copyright notices\nand license terms. Your use of these subcomponents is subject to the terms and\nconditions of the subcomponent's license, as noted in the LICENSE file.\n"
  },
  {
    "path": "modules/graph/README.md",
    "content": "## Introduction\n\n对于监控系统来讲，历史数据的存储，高效率查询，快速展现，是个很重要且困难的问题。这主要表现在下面三个方面：\n\n1. 数据量大：目前我们的监控系统，每个周期，大概有1亿次数据采集项上报（上报周期为1分钟和5分钟两种，各占50%），一天24小时里，从来不会有低峰，不管是白天和黑夜，每个周期，总会有那么多的数据要更新。\n2. 写操作多：一般的业务系统，通常都是读多写少，可以方便的使用各种缓存技术，再者各类数据库，对于查询操作的处理效率远远高于写操作。而监控系统恰恰相反，写操作远远高于读。每个周期几千万次的更新操作，对于常用数据库（MySQL、PostgreSQL、MongoDB）都不是最合适和擅长的。\n3. 高效率的查：我们说监控系统读操作少，是说相对写入来讲。监控系统本身对于读的要求很高，用户经常会有查询上百个metric，在过去一天、一周、一月、一年的数据。如何在秒级返回给用户并在前端展现，这是一个不小的挑战。\n\ngraph所做的事情，就是把用户每次push上来的数据，进行采样存储，并提供查询接口。\n\n我们参考RRDtool的理念，在数据每次存入的时候，会自动进行采样、归档。在默认的归档策略，一分钟push一次的频率下，历史数据保存5年。同时为了不丢失信息量，数据归档的时候，会按照平均值采样、最大值采样、最小值采样存三份。用户在查询某个metric，在过去一年的历史数据时，Graph会选择最合适的采样频率，返回采样过后的数据，提高了数据查询速度。\n\n## Installation\n\n源码安装过程，如下\n\n```bash\n# set $GOPATH and $GOROOT\n\nmkdir -p $GOPATH/src/github.com/open-falcon\ncd $GOPATH/src/github.com/open-falcon\ngit clone https://github.com/open-falcon/graph.git\n\ncd graph\ngo get ./...\n./control build\n\n./control start\n```\n\n你可以从[这里](https://github.com/open-falcon/graph/releases)，下载最新的release安装包，避免源码编译的种种问题。\n\n## Configuration\n\n    {\n        \"debug\": false, //true or false, 是否开启debug日志\n        \"http\": {\n            \"enabled\": true, //true or false, 表示是否开启该http端口，该端口为控制端口，主要用来对graph发送控制命令、统计命令、debug命令\n            \"listen\": \"0.0.0.0:6071\" //表示监听的http端口\n        },\n        \"rpc\": {\n            \"enabled\": true, //true or false, 表示是否开启该rpc端口，该端口为数据接收端口\n            \"listen\": \"0.0.0.0:6070\" //表示监听的rpc端口\n        },\n        \"rrd\": {\n            \"storage\": \"/home/work/data/6070\" //绝对路径，历史数据的文件存储路径（如有必要，请修改为合适的路）\n        },\n        \"db\": {\n            \"dsn\": \"root:@tcp(127.0.0.1:3306)/graph?loc=Local&parseTime=true\", //MySQL的连接信息，默认用户名是root，密码为空，host为127.0.0.1，database为graph（如有必要，请修改)\n            \"maxIdle\": 4  //MySQL连接池配置，连接池允许的最大连接数，保持默认即可\n        },\n        \"callTimeout\": 5000,  //RPC调用超时时间，单位ms\n        \"ioWorkerNum\": 64, //底层io.Worker的数量, 注意: 这个功能是v0.2.1版本之后引入的，v0.2.1版本之前的配置文件不需要该参数\n        \"migrate\": {  //扩容graph时历史数据自动迁移\n            \"enabled\": false,  //true or false, 表示graph是否处于数据迁移状态\n            \"concurrency\": 2, //数据迁移时的并发连接数，建议保持默认\n            \"replicas\": 500, //这是一致性hash算法需要的节点副本数量，建议不要变更，保持默认即可（必须和transfer的配置中保持一致）\n            \"cluster\": { //未扩容前老的graph实例列表\n                \"graph-00\" : \"127.0.0.1:6070\"\n            }\n        }\n    }\n\n## 关于扩容时数据自动迁移\n\n当graph集群扩容时，数据会自动迁移达到rebalance的目的。具体的操作步骤如下：\n\n假设1：旧的graph集群为\n```\ngraph-00 : 192.168.1.1:6070\ngraph-01 : 192.168.1.2:6070\n```\n\n假设2：在已有的graph集群基础上，需要再扩容两个实例，如下\n```\ngraph-00 : 192.168.1.1:6070\ngraph-01 : 192.168.1.2:6070\ngraph-02 : 192.168.1.3:6070\ngraph-03 : 192.168.1.4:6070\n```\n\n####1 修改新增加的graph的cfg.json如下：\n```python\n\"migrate\": {\n      \"enabled\": true,  //true 表示graph是否处于数据迁移状态\n      \"concurrency\": 2,\n      \"replicas\": 500,\n      \"cluster\": { //未扩容前老的graph实例列表\n         \"graph-00\" : \"192.168.1.1:6070\",\n         \"graph-01\" : \"192.168.1.2:6070\"\n      }\n}\n```\n> 要点说明:\n\n> 1. 只有新增加的graph实例配置需要修改，原有的graph实例配置不能变动\n\n> 2. 修改配置文件的时候，首先要把migrate -> enabled这个开关修改为true；其次要保证migrate -> cluster这个列表为旧集群的graph列表。\n\n\n####2 重启所有的graph\n\n```cd $WORKSPACE/graph/ && bash control restart```\n\n\n####3 修改所有transfer的cfg.json如下：\n\n```python\n\"graph\": {\n    \"enabled\": true,\n     ...,\n    \"replicas\": 500,\n    \"cluster\": {\n        \"graph-00\" : \"192.168.1.1:6070\",\n        \"graph-01\" : \"192.168.1.2:6070\",\n        \"graph-02\" : \"192.168.1.3:6070\",\n        \"graph-03\" : \"192.168.1.4:6070\"\n    }\n},\n```\n> 要点说明：最主要的就是修改graph -> cluster列表为扩容后完整的graph实例列表\n\n####4 重启所有的transfer\n\n```cd $WORKSPACE/transfer/ && bash control restart```\n\n> 这时候，transfer就会将接收到的数据，发送给扩容后的graph实例；同时graph实例，会自动进行数据的rebalance，rebalance的过程持续时间长短，与待迁移的counter数量以及graph机器的负载、性能有关系。\n\n####5 修改query的配置，并重启所有的query进程\n```python\n\"graph\": {\n     ...,\n    \"replicas\": 500,\n    \"cluster\": {\n        \"graph-00\" : \"192.168.1.1:6070\",\n        \"graph-01\" : \"192.168.1.2:6070\",\n        \"graph-02\" : \"192.168.1.3:6070\",\n        \"graph-03\" : \"192.168.1.4:6070\"\n    }\n},\n```\n> 要点说明：最主要的就是修改graph -> cluster列表为扩容后完整的graph实例列表\n\n\n\n####6 如何确认数据rebalance已经完成？\n\n目前只能通过观察graph内部的计数器，来判断整个数据迁移工作是否完成；观察方法如下：对所有新扩容的graph实例，访问其统计接口http://127.0.0.1:6071/counter/migrate 观察到所有的计数器都不再变化，那么就意味着迁移工作完成啦。\n"
  },
  {
    "path": "modules/graph/api/graph.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage api\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"time\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\n\tpfc \"github.com/niean/goperfcounter\"\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/index\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/proc\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/rrdtool\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/store\"\n)\n\ntype Graph int\n\nfunc (this *Graph) GetRrd(key string, rrdfile *g.File) (err error) {\n\tvar (\n\t\tmd5    string\n\t\tdsType string\n\t\tstep   int\n\t)\n\tif md5, dsType, step, err = g.SplitRrdCacheKey(key); err != nil {\n\t\treturn err\n\t} else {\n\t\trrdfile.Filename = g.RrdFileName(g.Config().RRD.Storage, md5, dsType, step)\n\t}\n\n\titems := store.GraphItems.PopAll(key)\n\tif len(items) > 0 {\n\t\trrdtool.FlushFile(rrdfile.Filename, md5, items)\n\t}\n\n\trrdfile.Body, err = rrdtool.ReadFile(rrdfile.Filename, md5)\n\treturn\n}\n\nfunc (this *Graph) Ping(req cmodel.NullRpcRequest, resp *cmodel.SimpleRpcResponse) error {\n\treturn nil\n}\n\nfunc (this *Graph) Send(items []*cmodel.GraphItem, resp *cmodel.SimpleRpcResponse) error {\n\tgo handleItems(items)\n\treturn nil\n}\n\n// 供外部调用、处理接收到的数据 的接口\nfunc HandleItems(items []*cmodel.GraphItem) error {\n\thandleItems(items)\n\treturn nil\n}\n\nfunc handleItems(items []*cmodel.GraphItem) {\n\tif items == nil {\n\t\treturn\n\t}\n\n\tcount := len(items)\n\tif count == 0 {\n\t\treturn\n\t}\n\n\tcfg := g.Config()\n\n\tfor i := 0; i < count; i++ {\n\t\tif items[i] == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tendpoint := items[i].Endpoint\n\t\tif !g.IsValidString(endpoint) {\n\t\t\tlog.Debugf(\"invalid endpoint: %s\", endpoint)\n\t\t\tpfc.Meter(\"invalidEnpoint\", 1)\n\t\t\tcontinue\n\t\t}\n\n\t\tcounter := cutils.Counter(items[i].Metric, items[i].Tags)\n\t\tif !g.IsValidString(counter) {\n\t\t\tlog.Debugf(\"invalid counter: %s/%s\", endpoint, counter)\n\t\t\tpfc.Meter(\"invalidCounter\", 1)\n\t\t\tcontinue\n\t\t}\n\n\t\tdsType := items[i].DsType\n\t\tstep := items[i].Step\n\t\tchecksum := items[i].Checksum()\n\t\tkey := g.FormRrdCacheKey(checksum, dsType, step)\n\n\t\t//statistics\n\t\tproc.GraphRpcRecvCnt.Incr()\n\n\t\t// To Graph\n\t\tfirst := store.GraphItems.First(key)\n\t\tif first != nil && items[i].Timestamp <= first.Timestamp {\n\t\t\tcontinue\n\t\t}\n\t\tstore.GraphItems.PushFront(key, items[i], checksum, cfg)\n\n\t\t// To Index\n\t\tindex.ReceiveItem(items[i], checksum)\n\n\t\t// To History\n\t\tstore.AddItem(checksum, items[i])\n\t}\n}\n\nfunc (this *Graph) Query(param cmodel.GraphQueryParam, resp *cmodel.GraphQueryResponse) error {\n\tvar (\n\t\tdatas      []*cmodel.RRDData\n\t\tdatas_size int\n\t)\n\n\t// statistics\n\tproc.GraphQueryCnt.Incr()\n\n\tcfg := g.Config()\n\n\t// form empty response\n\tresp.Values = []*cmodel.RRDData{}\n\tresp.Endpoint = param.Endpoint\n\tresp.Counter = param.Counter\n\tdsType, step, exists := index.GetTypeAndStep(param.Endpoint, param.Counter) // complete dsType and step\n\tif !exists {\n\t\treturn nil\n\t}\n\tresp.DsType = dsType\n\tresp.Step = step\n\n\tstart_ts := param.Start - param.Start%int64(step)\n\tend_ts := param.End - param.End%int64(step) + int64(step)\n\tif end_ts-start_ts-int64(step) < 1 {\n\t\treturn nil\n\t}\n\n\tmd5 := cutils.Md5(param.Endpoint + \"/\" + param.Counter)\n\tkey := g.FormRrdCacheKey(md5, dsType, step)\n\tfilename := g.RrdFileName(cfg.RRD.Storage, md5, dsType, step)\n\n\t// read cached items\n\titems, flag := store.GraphItems.FetchAll(key)\n\titems_size := len(items)\n\n\tif cfg.Migrate.Enabled && flag&g.GRAPH_F_MISS != 0 {\n\t\tnode, _ := rrdtool.Consistent.Get(param.Endpoint + \"/\" + param.Counter)\n\t\tdone := make(chan error, 1)\n\t\tres := &cmodel.GraphAccurateQueryResponse{}\n\t\trrdtool.Net_task_ch[node] <- &rrdtool.Net_task_t{\n\t\t\tMethod: rrdtool.NET_TASK_M_QUERY,\n\t\t\tDone:   done,\n\t\t\tArgs:   param,\n\t\t\tReply:  res,\n\t\t}\n\t\t<-done\n\t\t// fetch data from remote\n\t\tdatas = res.Values\n\t\tdatas_size = len(datas)\n\t} else {\n\t\t// read data from rrd file\n\t\t// 从RRD中获取数据不包含起始时间点\n\t\t// 例: start_ts=1484651400,step=60,则第一个数据时间为1484651460)\n\t\tdatas, _ = rrdtool.Fetch(filename, md5, param.ConsolFun, start_ts-int64(step), end_ts, step)\n\t\tdatas_size = len(datas)\n\t}\n\n\tnowTs := time.Now().Unix()\n\tlastUpTs := nowTs - nowTs%int64(step)\n\trra1StartTs := lastUpTs - int64(rrdtool.RRA1PointCnt*step)\n\n\t// consolidated, do not merge\n\tif start_ts < rra1StartTs {\n\t\tresp.Values = datas\n\t\tgoto _RETURN_OK\n\t}\n\n\t// no cached items, do not merge\n\tif items_size < 1 {\n\t\tresp.Values = datas\n\t\tgoto _RETURN_OK\n\t}\n\n\t// merge\n\t{\n\t\t// fmt cached items\n\t\tvar val cmodel.JsonFloat\n\t\tcache := make([]*cmodel.RRDData, 0)\n\n\t\tts := items[0].Timestamp\n\t\titemEndTs := items[items_size-1].Timestamp\n\t\titemIdx := 0\n\t\tif dsType == g.DERIVE || dsType == g.COUNTER {\n\t\t\tfor ts < itemEndTs {\n\t\t\t\tif itemIdx < items_size-1 && ts == items[itemIdx].Timestamp {\n\t\t\t\t\tif ts == items[itemIdx+1].Timestamp-int64(step) && items[itemIdx+1].Value >= items[itemIdx].Value {\n\t\t\t\t\t\tval = cmodel.JsonFloat(items[itemIdx+1].Value-items[itemIdx].Value) / cmodel.JsonFloat(step)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tval = cmodel.JsonFloat(math.NaN())\n\t\t\t\t\t}\n\t\t\t\t\titemIdx++\n\t\t\t\t} else {\n\t\t\t\t\t// missing\n\t\t\t\t\tval = cmodel.JsonFloat(math.NaN())\n\t\t\t\t}\n\n\t\t\t\tif ts >= start_ts && ts <= end_ts {\n\t\t\t\t\tcache = append(cache, &cmodel.RRDData{Timestamp: ts, Value: val})\n\t\t\t\t}\n\t\t\t\tts = ts + int64(step)\n\t\t\t}\n\t\t} else if dsType == g.GAUGE {\n\t\t\tfor ts <= itemEndTs {\n\t\t\t\tif itemIdx < items_size && ts == items[itemIdx].Timestamp {\n\t\t\t\t\tval = cmodel.JsonFloat(items[itemIdx].Value)\n\t\t\t\t\titemIdx++\n\t\t\t\t} else {\n\t\t\t\t\t// missing\n\t\t\t\t\tval = cmodel.JsonFloat(math.NaN())\n\t\t\t\t}\n\n\t\t\t\tif ts >= start_ts && ts <= end_ts {\n\t\t\t\t\tcache = append(cache, &cmodel.RRDData{Timestamp: ts, Value: val})\n\t\t\t\t}\n\t\t\t\tts = ts + int64(step)\n\t\t\t}\n\t\t}\n\t\tcache_size := len(cache)\n\n\t\t// do merging\n\t\tmerged := make([]*cmodel.RRDData, 0)\n\t\tif datas_size > 0 {\n\t\t\tfor _, val := range datas {\n\t\t\t\tif val.Timestamp >= start_ts && val.Timestamp <= end_ts {\n\t\t\t\t\tmerged = append(merged, val) //rrdtool返回的数据,时间戳是连续的、不会有跳点的情况\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif cache_size > 0 {\n\t\t\trrdDataSize := len(merged)\n\t\t\tlastTs := cache[0].Timestamp\n\n\t\t\t// find junction\n\t\t\trrdDataIdx := 0\n\t\t\tfor rrdDataIdx = rrdDataSize - 1; rrdDataIdx >= 0; rrdDataIdx-- {\n\t\t\t\tif merged[rrdDataIdx].Timestamp < cache[0].Timestamp {\n\t\t\t\t\tlastTs = merged[rrdDataIdx].Timestamp\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// fix missing\n\t\t\tfor ts := lastTs + int64(step); ts < cache[0].Timestamp; ts += int64(step) {\n\t\t\t\tmerged = append(merged, &cmodel.RRDData{Timestamp: ts, Value: cmodel.JsonFloat(math.NaN())})\n\t\t\t}\n\n\t\t\t// merge cached items to result\n\t\t\trrdDataIdx += 1\n\t\t\tfor cacheIdx := 0; cacheIdx < cache_size; cacheIdx++ {\n\t\t\t\tif rrdDataIdx < rrdDataSize {\n\t\t\t\t\tif !math.IsNaN(float64(cache[cacheIdx].Value)) {\n\t\t\t\t\t\tmerged[rrdDataIdx] = cache[cacheIdx]\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tmerged = append(merged, cache[cacheIdx])\n\t\t\t\t}\n\t\t\t\trrdDataIdx++\n\t\t\t}\n\t\t}\n\t\tmergedSize := len(merged)\n\n\t\t// fmt result\n\t\tret_size := int((end_ts - start_ts) / int64(step))\n\t\tif dsType == g.GAUGE {\n\t\t\tret_size += 1\n\t\t}\n\t\tret := make([]*cmodel.RRDData, ret_size, ret_size)\n\t\tmergedIdx := 0\n\t\tts = start_ts\n\t\tfor i := 0; i < ret_size; i++ {\n\t\t\tif mergedIdx < mergedSize && ts == merged[mergedIdx].Timestamp {\n\t\t\t\tret[i] = merged[mergedIdx]\n\t\t\t\tmergedIdx++\n\t\t\t} else {\n\t\t\t\tret[i] = &cmodel.RRDData{Timestamp: ts, Value: cmodel.JsonFloat(math.NaN())}\n\t\t\t}\n\t\t\tts += int64(step)\n\t\t}\n\t\tresp.Values = ret\n\t}\n\n_RETURN_OK:\n\t// statistics\n\tproc.GraphQueryItemCnt.IncrBy(int64(len(resp.Values)))\n\treturn nil\n}\n\n//从内存索引、MySQL中删除counter，并从磁盘上删除对应rrd文件\nfunc (this *Graph) Delete(params []*cmodel.GraphDeleteParam, resp *cmodel.GraphDeleteResp) error {\n\tresp = &cmodel.GraphDeleteResp{}\n\tfor _, param := range params {\n\t\terr, tags := cutils.SplitTagsString(param.Tags)\n\t\tif err != nil {\n\t\t\tlog.Error(\"invalid tags:\", param.Tags, \"error:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tvar item *cmodel.GraphItem = &cmodel.GraphItem{\n\t\t\tEndpoint: param.Endpoint,\n\t\t\tMetric:   param.Metric,\n\t\t\tTags:     tags,\n\t\t\tDsType:   param.DsType,\n\t\t\tStep:     param.Step,\n\t\t}\n\t\tindex.RemoveItem(item)\n\t}\n\n\treturn nil\n}\n\nfunc (this *Graph) Info(param cmodel.GraphInfoParam, resp *cmodel.GraphInfoResp) error {\n\t// statistics\n\tproc.GraphInfoCnt.Incr()\n\n\tdsType, step, exists := index.GetTypeAndStep(param.Endpoint, param.Counter)\n\tif !exists {\n\t\treturn nil\n\t}\n\n\tmd5 := cutils.Md5(param.Endpoint + \"/\" + param.Counter)\n\tfilename := fmt.Sprintf(\"%s/%s/%s_%s_%d.rrd\", g.Config().RRD.Storage, md5[0:2], md5, dsType, step)\n\n\tresp.ConsolFun = dsType\n\tresp.Step = step\n\tresp.Filename = filename\n\n\treturn nil\n}\n\nfunc (this *Graph) Last(param cmodel.GraphLastParam, resp *cmodel.GraphLastResp) error {\n\t// statistics\n\tproc.GraphLastCnt.Incr()\n\n\tresp.Endpoint = param.Endpoint\n\tresp.Counter = param.Counter\n\tresp.Value = GetLast(param.Endpoint, param.Counter)\n\n\treturn nil\n}\n\nfunc (this *Graph) LastRaw(param cmodel.GraphLastParam, resp *cmodel.GraphLastResp) error {\n\t// statistics\n\tproc.GraphLastRawCnt.Incr()\n\n\tresp.Endpoint = param.Endpoint\n\tresp.Counter = param.Counter\n\tresp.Value = GetLastRaw(param.Endpoint, param.Counter)\n\n\treturn nil\n}\n\n// 非法值: ts=0,value无意义\nfunc GetLast(endpoint, counter string) *cmodel.RRDData {\n\tdsType, step, exists := index.GetTypeAndStep(endpoint, counter)\n\tif !exists {\n\t\treturn cmodel.NewRRDData(0, 0.0)\n\t}\n\n\tif dsType == g.GAUGE {\n\t\treturn GetLastRaw(endpoint, counter)\n\t}\n\n\tif dsType == g.COUNTER || dsType == g.DERIVE {\n\t\tmd5 := cutils.Md5(endpoint + \"/\" + counter)\n\t\titems := store.GetAllItems(md5)\n\t\tif len(items) < 2 {\n\t\t\treturn cmodel.NewRRDData(0, 0.0)\n\t\t}\n\n\t\tf0 := items[0]\n\t\tf1 := items[1]\n\t\tdelta_ts := f0.Timestamp - f1.Timestamp\n\t\tdelta_v := f0.Value - f1.Value\n\t\tif delta_ts != int64(step) || delta_ts <= 0 {\n\t\t\treturn cmodel.NewRRDData(0, 0.0)\n\t\t}\n\t\tif delta_v < 0 {\n\t\t\t// when cnt restarted, new cnt value would be zero, so fix it here\n\t\t\tdelta_v = 0\n\t\t}\n\n\t\treturn cmodel.NewRRDData(f0.Timestamp, delta_v/float64(delta_ts))\n\t}\n\n\treturn cmodel.NewRRDData(0, 0.0)\n}\n\n// 非法值: ts=0,value无意义\nfunc GetLastRaw(endpoint, counter string) *cmodel.RRDData {\n\tmd5 := cutils.Md5(endpoint + \"/\" + counter)\n\titem := store.GetLastItem(md5)\n\treturn cmodel.NewRRDData(item.Timestamp, item.Value)\n}\n"
  },
  {
    "path": "modules/graph/api/rpc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage api\n\nimport (\n\t\"container/list\"\n\t\"log\"\n\t\"net\"\n\t\"net/rpc\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n)\n\ntype conn_list struct {\n\tsync.RWMutex\n\tlist *list.List\n}\n\nfunc (l *conn_list) insert(c net.Conn) *list.Element {\n\tl.Lock()\n\tdefer l.Unlock()\n\treturn l.list.PushBack(c)\n}\nfunc (l *conn_list) remove(e *list.Element) net.Conn {\n\tl.Lock()\n\tdefer l.Unlock()\n\treturn l.list.Remove(e).(net.Conn)\n}\n\nvar Close_chan, Close_done_chan chan int\nvar connects conn_list\n\nfunc init() {\n\tClose_chan = make(chan int, 1)\n\tClose_done_chan = make(chan int, 1)\n\tconnects = conn_list{list: list.New()}\n}\n\nfunc Start() {\n\tif !g.Config().Rpc.Enabled {\n\t\tlog.Println(\"rpc.Start warning, not enabled\")\n\t\treturn\n\t}\n\taddr := g.Config().Rpc.Listen\n\ttcpAddr, err := net.ResolveTCPAddr(\"tcp\", addr)\n\tif err != nil {\n\t\tlog.Fatalf(\"rpc.Start error, net.ResolveTCPAddr failed, %s\", err)\n\t}\n\n\tlistener, err := net.ListenTCP(\"tcp\", tcpAddr)\n\tif err != nil {\n\t\tlog.Fatalf(\"rpc.Start error, listen %s failed, %s\", addr, err)\n\t} else {\n\t\tlog.Println(\"rpc.Start ok, listening on\", addr)\n\t}\n\n\trpc.Register(new(Graph))\n\n\tgo func() {\n\t\tvar tempDelay time.Duration // how long to sleep on accept failure\n\t\tfor {\n\t\t\tconn, err := listener.AcceptTCP()\n\t\t\tif err != nil {\n\t\t\t\tif tempDelay == 0 {\n\t\t\t\t\ttempDelay = 5 * time.Millisecond\n\t\t\t\t} else {\n\t\t\t\t\ttempDelay *= 2\n\t\t\t\t}\n\t\t\t\tif max := 1 * time.Second; tempDelay > max {\n\t\t\t\t\ttempDelay = max\n\t\t\t\t}\n\t\t\t\ttime.Sleep(tempDelay)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconn.SetKeepAlive(true)\n\t\t\ttempDelay = 0\n\t\t\tgo func() {\n\t\t\t\te := connects.insert(conn)\n\t\t\t\tdefer connects.remove(e)\n\t\t\t\trpc.ServeConn(conn)\n\t\t\t}()\n\t\t}\n\t}()\n\n\tselect {\n\tcase <-Close_chan:\n\t\tlog.Println(\"rpc, recv sigout and exiting...\")\n\t\tlistener.Close()\n\t\tClose_done_chan <- 1\n\n\t\tconnects.Lock()\n\t\tfor e := connects.list.Front(); e != nil; e = e.Next() {\n\t\t\te.Value.(net.Conn).Close()\n\t\t}\n\t\tconnects.Unlock()\n\n\t\treturn\n\t}\n\n}\n"
  },
  {
    "path": "modules/graph/cfg.example.json",
    "content": "{\n\t\"debug\": false,\n\t\"http\": {\n\t\t\"enabled\": true,\n\t\t\"listen\": \"0.0.0.0:6071\"\n\t},\n\t\"rpc\": {\n\t\t\"enabled\": true,\n\t\t\"listen\": \"0.0.0.0:6070\"\n\t},\n\t\"rrd\": {\n\t\t\"storage\": \"./data/6070\"\n\t},\n\t\"db\": {\n\t\t\"dsn\": \"root:@tcp(127.0.0.1:3306)/graph?loc=Local&parseTime=true\",\n\t\t\"maxIdle\": 4\n\t},\n\t\"callTimeout\": 5000,\n\t\"ioWorkerNum\": 64,\n\t\"migrate\": {\n\t\t\"enabled\": false,\n\t\t\"concurrency\": 2,\n\t\t\"replicas\": 500,\n\t\t\"cluster\": {\n\t\t\t\"graph-00\" : \"127.0.0.1:6070\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/graph/control",
    "content": "#!/bin/bash\nworkspace=$(cd $(dirname $0) && pwd)\ncd $workspace\n\nmodule=graph\napp=falcon-$module\nconf=cfg.json\npidfile=var/app.pid\nlogfile=var/app.log\n\nmkdir -p var &>/dev/null\n\n\n## build & pack\nfunction build() {\n    commit=$(git log -1 --pretty=%h)\n    cat <<EOF > ./g/git.go\npackage g\nconst (\n    COMMIT = \"$commit\"\n)\nEOF\n    go build -o $app main.go\n    sc=$?\n    if [ $sc -ne 0 ];then\n        echo \"build error\"\n        exit $sc\n    else\n        echo -n \"build ok, vsn=\" \n        ./$app -v \n    fi\n}\n\nfunction pack() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-$version.tar.gz control $app cfg.example.json gitversion ./test/debug\n    rm -f gitversion &>/dev/null\n}\n\nfunction packbin() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-bin-$version.tar.gz $app gitversion\n    rm -f gitversion &>/dev/null\n}\n\n## opt\nfunction start() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"started, pid=\"\n        cat $pidfile\n        return 1\n    fi\n\n    nohup ./$app -c $conf >>$logfile 2>&1 &\n    echo $! > $pidfile\n    echo \"start ok, pid=$!\"\n}\n\nfunction stop() {\n    pid=`cat $pidfile`\n    kill $pid\n    echo \"stopped\"\n}\n\nfunction shutdown() {\n    pid=`cat $pidfile`\n    kill -9 $pid\n    echo \"stopped\"\n}\n\nfunction restart() {\n    stop\n    sleep 1\n    start\n}\n\n## other\nfunction status() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"running, pid=\"\n        cat $pidfile\n    else\n        echo \"stopped\"\n    fi\n}\n\nfunction version() {\n    ./$app -vg\n}\n\nfunction tailf() {\n    tail -f $logfile\n}\n\n## internal\nfunction check_pid() {\n    if [ -f $pidfile ];then\n        pid=`cat $pidfile`\n        if [ -n $pid ]; then\n            running=`ps -p $pid|grep -v \"PID TTY\" |wc -l`\n            return $running\n        fi\n    fi\n    return 0\n}\n\n## usage\nfunction usage() {\n    echo \"$0 build|pack|packbin|start|stop|restart|status|tail|version\"\n}\n\n## main\naction=$1\ncase $action in\n    ## build\n    \"build\" )\n        build\n        ;;\n    \"pack\" )\n        pack\n        ;;\n    \"packbin\" )\n        packbin\n        ;;\n    ## opt\n    \"start\" )\n        start\n        ;;\n    \"stop\" )\n        stop\n        ;;\n    \"kill\" )\n        shutdown\n        ;;\n    \"restart\" )\n        restart\n        ;;\n    ## other\n    \"status\" )\n        status\n        ;;\n    \"version\" )\n        version\n        ;;\n    \"tail\" )\n        tailf\n        ;;\n    * )\n        usage\n        ;;\nesac\n"
  },
  {
    "path": "modules/graph/cron/clean.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// Copyright 2016 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"log\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/index\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/store\"\n\n\tpfc \"github.com/niean/goperfcounter\"\n)\n\nfunc CleanCache() {\n\n\tticker := time.NewTicker(time.Duration(g.CLEAN_CACHE) * time.Second)\n\tdefer ticker.Stop()\n\tfor {\n\t\t<-ticker.C\n\t\tDeleteInvalidItems()   // 删除无效的GraphItems\n\t\tDeleteInvalidHistory() // 删除无效的HistoryCache\n\t}\n}\n\n/*\n\n  概念定义及结构体简谱:\n  ckey = md5_type_step\n  uuid = endpoint/metric/tags/dstype/step\n  md5  = md5(endpoint/metric/tags)\n\n  GraphItems        [idx]  [ckey] [{timestamp, value}, {timestamp, value} ...]\n  HistoryCache      [md5]  [itemFirst, itemSecond]\n  IndexedItemCache  [md5]  {UUID, Item}\n\n*/\n\n// TODO: 删除长期不更新数据(依赖index)\nfunc DeleteInvalidItems() int {\n\n\tvar currentCnt, deleteCnt int\n\tgraphItems := store.GraphItems\n\n\tfor idx := 0; idx < graphItems.Size; idx++ {\n\t\tkeys := graphItems.KeysByIndex(idx)\n\n\t\tfor _, key := range keys {\n\t\t\ttmp := strings.Split(key, \"_\") // key = md5_type_step\n\t\t\tif len(tmp) == 3 && !index.IndexedItemCache.ContainsKey(tmp[0]) {\n\t\t\t\tgraphItems.Remove(key)\n\t\t\t\tdeleteCnt++\n\t\t\t}\n\t\t}\n\t}\n\tcurrentCnt = graphItems.Len()\n\n\tpfc.Gauge(\"GraphItemsCacheCnt\", int64(currentCnt))\n\tpfc.Gauge(\"GraphItemsCacheInvalidCnt\", int64(deleteCnt))\n\tlog.Printf(\"GraphItemsCache: Count=>%d, DeleteInvalid=>%d\", currentCnt, deleteCnt)\n\n\treturn deleteCnt\n}\n\n// TODO: 删除长期不更新数据(依赖index)\nfunc DeleteInvalidHistory() int {\n\n\tvar currentCnt, deleteCnt int\n\thistoryCache := store.HistoryCache\n\n\tkeys := historyCache.Keys()\n\tfor _, key := range keys {\n\t\tif !index.IndexedItemCache.ContainsKey(key) {\n\t\t\thistoryCache.Remove(key)\n\t\t\tdeleteCnt++\n\t\t}\n\t}\n\tcurrentCnt = historyCache.Size()\n\n\tpfc.Gauge(\"HistoryCacheCnt\", int64(currentCnt))\n\tpfc.Gauge(\"HistoryCacheInvalidCnt\", int64(deleteCnt))\n\tlog.Printf(\"HistoryCache: Count=>%d, DeleteInvalid=>%d\", currentCnt, deleteCnt)\n\n\treturn deleteCnt\n}\n"
  },
  {
    "path": "modules/graph/doc/README.md",
    "content": "# Graph\n\ngraph组件，负责存储监控绘图数据。\n\n## 功能描述\n----\ngraph组件，使用rrdtool，来存储监控历史数据。主要功能，如下：\n\n0. 提供Golang-RPC接口，接收格式化的监控数据。监控数据的格式，见[这里](http://blog.niean.name/2015/08/06/falcon-intro/#数据模型)。\n1. 支持存储原始数据。默认保存12H的原始数据。\n2. 支持对原始数据进行归档存储。支持5min、20min、3h、12h四个归档粒度。\n3. 提供Http-Get和Golang-Rpc两种接口，用于查询历史数据。查询数据时，graph会自适应选择归档粒度，使返回的数据点不过多。\n\n\n## 模块结构\n----\ngraph主要的模块结构（含数据流）如下。\n\n![falcon.graph.arch](https://raw.githubusercontent.com/niean/niean.common.store/master/images/open-falcon/graph/graph.arch.png)\n\ngraph的模块，主要分为两个功能：数据接收、数据查询。\n\n#### 数据接收\n\ngraph对外提供了golang-rpc形式的接口，用于接收外部push过来的监控数据。收到的数据，被复制到索引生成器`index`一份、被复制到接收缓存`recv cache`一份。索引生成器，会为新增的监控数据建立一条索引信息（形如`endpoint/metric/tags`），并存储到外部的mysql数据库中、供dashboard等系统使用。接收缓存，是监控数据被写入磁盘`rrdfile`前的一个缓存，目的是优化磁盘写入性能。\n\n#### 数据查询\ngraph对外提供了golang-rpc形式的接口，用于接收外部的查询请求。query模块，会使用索引信息来验证外部请求的counter合法性，验证通过后，读取磁盘上`rrdfile`内容、并merge接收缓存中尚未flush到磁盘的监控数据，得到完整的结果后 返回给外部。\n\n\n## 部署实践\n----\n\ngraph消耗的主要资源是disk，同时会消耗部分mem和cpu。可以根据监控指标个数，来预估graph集群的容量。默认的，graph资源消耗的一个参考值，如下。\n\n|监控指标量|磁盘空间|磁盘写|磁盘读|内存|CPU|\n|:----|:----|:----|:----|:----|:----|\n|10K条|1GB|100KB/s|150KB/s|125MB|0.05核|\n\n建议，部署graph组建的服务器，配置较大容量的SSD硬盘。\n\n\n## 扩容\n----\n系统扩容时，只需求改transfer和query的graph集群配置即可，graph组件会自动完成历史数据迁移的工作。扩容期间，graph可以正常的对外提供服务。\n\n\n## 缺点\n----\n\n1. 对磁盘资源消耗严重。rrdtool自带的归档功能，会消耗大量的磁盘IO。\n2. 精确的历史数据保存时间短，不利于历史的现场回放。默认只保存12H的原始数据。\n3. 绘图数据的高可用，实现成本较高。冷备、热备绘图数据都多多少少存在一些问题，灾难恢复也可能需要较多的时间。\n\n\n"
  },
  {
    "path": "modules/graph/g/cfg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"strconv\"\n\t\"sync/atomic\"\n\t\"unsafe\"\n\n\t\"github.com/toolkits/file\"\n)\n\ntype File struct {\n\tFilename string\n\tBody     []byte\n}\n\ntype HttpConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype RpcConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype RRDConfig struct {\n\tStorage string `json:\"storage\"`\n}\n\ntype DBConfig struct {\n\tDsn     string `json:\"dsn\"`\n\tMaxIdle int    `json:\"maxIdle\"`\n}\n\ntype GlobalConfig struct {\n\tPid            string      `json:\"pid\"`\n\tDebug          bool        `json:\"debug\"`\n\tHttp           *HttpConfig `json:\"http\"`\n\tRpc            *RpcConfig  `json:\"rpc\"`\n\tRRD            *RRDConfig  `json:\"rrd\"`\n\tDB             *DBConfig   `json:\"db\"`\n\tCallTimeout    int32       `json:\"callTimeout\"`\n\tIOWorkerNum    int         `json:\"ioWorkerNum\"`\n\tFirstBytesSize int\n\tMigrate        struct {\n\t\tConcurrency int               `json:\"concurrency\"` //number of multiple worker per node\n\t\tEnabled     bool              `json:\"enabled\"`\n\t\tReplicas    int               `json:\"replicas\"`\n\t\tCluster     map[string]string `json:\"cluster\"`\n\t} `json:\"migrate\"`\n}\n\nvar (\n\tConfigFile string\n\tptr        unsafe.Pointer\n)\n\nfunc Config() *GlobalConfig {\n\treturn (*GlobalConfig)(atomic.LoadPointer(&ptr))\n}\n\nfunc ParseConfig(cfg string) {\n\tif cfg == \"\" {\n\t\tlog.Fatalln(\"config file not specified: use -c $filename\")\n\t}\n\n\tif !file.IsExist(cfg) {\n\t\tlog.Fatalln(\"config file specified not found:\", cfg)\n\t}\n\n\tConfigFile = cfg\n\n\tconfigContent, err := file.ToTrimString(cfg)\n\tif err != nil {\n\t\tlog.Fatalln(\"read config file\", cfg, \"error:\", err.Error())\n\t}\n\n\tvar c GlobalConfig\n\terr = json.Unmarshal([]byte(configContent), &c)\n\tif err != nil {\n\t\tlog.Fatalln(\"parse config file\", cfg, \"error:\", err.Error())\n\t}\n\n\tif c.Migrate.Enabled && len(c.Migrate.Cluster) == 0 {\n\t\tc.Migrate.Enabled = false\n\t}\n\n\t// 确保ioWorkerNum是2^N\n\tif c.IOWorkerNum == 0 || (c.IOWorkerNum&(c.IOWorkerNum-1) != 0) {\n\t\tlog.Fatalf(\"IOWorkerNum must be 2^N, current IOWorkerNum is %v\", c.IOWorkerNum)\n\t}\n\n\t// 需要md5的前多少位参与ioWorker的分片计算\n\tc.FirstBytesSize = len(strconv.FormatInt(int64(c.IOWorkerNum), 16))\n\n\t// set config\n\tatomic.StorePointer(&ptr, unsafe.Pointer(&c))\n\n\tlog.Println(\"g.ParseConfig ok, file\", cfg)\n}\n"
  },
  {
    "path": "modules/graph/g/db.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"database/sql\"\n\t_ \"github.com/go-sql-driver/mysql\"\n\t\"log\"\n\t\"sync\"\n)\n\n// TODO 草草的写了一个db连接池,优化下\nvar (\n\tdbLock    sync.RWMutex\n\tdbConnMap map[string]*sql.DB\n)\n\nvar DB *sql.DB\n\nfunc InitDB() {\n\tvar err error\n\tDB, err = makeDbConn()\n\tif DB == nil || err != nil {\n\t\tlog.Fatalln(\"g.InitDB, get db conn fail\", err)\n\t}\n\n\tdbConnMap = make(map[string]*sql.DB)\n\tlog.Println(\"g.InitDB ok\")\n}\n\nfunc GetDbConn(connName string) (c *sql.DB, e error) {\n\tdbLock.Lock()\n\tdefer dbLock.Unlock()\n\n\tvar err error\n\tvar dbConn *sql.DB\n\tdbConn = dbConnMap[connName]\n\tif dbConn == nil {\n\t\tdbConn, err = makeDbConn()\n\t\tif dbConn == nil || err != nil {\n\t\t\tcloseDbConn(dbConn)\n\t\t\treturn nil, err\n\t\t}\n\t\tdbConnMap[connName] = dbConn\n\t}\n\n\terr = dbConn.Ping()\n\tif err != nil {\n\t\tcloseDbConn(dbConn)\n\t\tdelete(dbConnMap, connName)\n\t\treturn nil, err\n\t}\n\n\treturn dbConn, err\n}\n\n// 创建一个新的mysql连接\nfunc makeDbConn() (conn *sql.DB, err error) {\n\tconn, err = sql.Open(\"mysql\", Config().DB.Dsn)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconn.SetMaxIdleConns(Config().DB.MaxIdle)\n\terr = conn.Ping()\n\n\treturn conn, err\n}\n\nfunc closeDbConn(conn *sql.DB) {\n\tif conn != nil {\n\t\tconn.Close()\n\t}\n}\n"
  },
  {
    "path": "modules/graph/g/g.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"runtime\"\n)\n\n// TODO\n// change graph.store cache struct(key: md5->uuid)\n// flush when query happens seems unreasonable\n// shrink packages\n\n// CHANGE LOGS\n// 0.4.8 fix filename bug emporarily, fix dirty-index-cache bug of query,\n//\t\t add filter for debug\n// 0.4.9 mv db back to g, add rpc.last\n// 0.5.0 rm trace, add history&last api\n// 0.5.1 add http interface v2, using form args\n// 0.5.2 add last_raw\n// 0.5.3 fix bug of last&last_raw\n// 0.5.4 fix bug of Query.merge\n// 0.5.5 use commom(rm model), fix sync disk\n// 0.5.7 set xff to 0 from 0.5, in order to support irregular step counter\n// 0.5.8 clean GraphItems/historyCache Cache at regular intervals\n// 0.5.9 add flush style(flush by number of every counter's monitoring data)\n\nvar (\n\tBinaryName string\n\tVersion    string\n\tGitCommit  string\n)\n\nfunc VersionMsg() string {\n\treturn Version + \"@\" + GitCommit\n}\n\nconst (\n\tGAUGE           = \"GAUGE\"\n\tDERIVE          = \"DERIVE\"\n\tCOUNTER         = \"COUNTER\"\n\tDEFAULT_STEP    = 60      //s\n\tMIN_STEP        = 30      //s\n\tCLEAN_CACHE     = 86400   //s the step that clean GraphItems/historyCache Cache\n\tCACHE_DELAY     = 1800    //s\n\tCACHE_TIME      = 1800000 //ms\n\tFLUSH_DISK_STEP = 1000    //ms\n\tFLUSH_MIN_COUNT = 6       //  flush counter to disk when its number of monitoring data greater than FLUSH_MIN_COUNT\n\tFLUSH_MAX_WAIT  = 86400   //s flush counter to disk if it not be flushed within FLUSH_MAX_WAIT seconds\n)\n\nconst (\n\tGRAPH_F_MISS uint32 = 1 << iota\n\tGRAPH_F_ERR\n\tGRAPH_F_SENDING\n\tGRAPH_F_FETCHING\n)\n\nfunc init() {\n\truntime.GOMAXPROCS(runtime.NumCPU())\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)\n}\n"
  },
  {
    "path": "modules/graph/g/git.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nconst (\n\tCOMMIT = \"gitversion\"\n)\n"
  },
  {
    "path": "modules/graph/g/logger.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport log \"github.com/sirupsen/logrus\"\n\nfunc InitLog(level string) (err error) {\n\tswitch level {\n\tcase \"info\":\n\t\tlog.SetLevel(log.InfoLevel)\n\tcase \"debug\":\n\t\tlog.SetLevel(log.DebugLevel)\n\tcase \"warn\":\n\t\tlog.SetLevel(log.WarnLevel)\n\tdefault:\n\t\tlog.Fatal(\"log conf only allow [info, debug, warn], please check your confguire\")\n\t}\n\treturn\n}\n"
  },
  {
    "path": "modules/graph/g/utils.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/toolkits/file\"\n)\n\n// RRDTOOL UTILS\n// 监控数据对应的rrd文件名称\nfunc RrdFileName(baseDir string, md5 string, dsType string, step int) string {\n\treturn baseDir + \"/\" + md5[0:2] + \"/\" +\n\t\tmd5 + \"_\" + dsType + \"_\" + strconv.Itoa(step) + \".rrd\"\n}\n\n// rrd文件是否存在\nfunc IsRrdFileExist(filename string) bool {\n\treturn file.IsExist(filename)\n}\n\n// 生成rrd缓存数据的key\nfunc FormRrdCacheKey(md5 string, dsType string, step int) string {\n\treturn md5 + \"_\" + dsType + \"_\" + strconv.Itoa(step)\n}\nfunc SplitRrdCacheKey(ckey string) (md5 string, dsType string, step int, err error) {\n\tckey_slice := strings.Split(ckey, \"_\")\n\tif len(ckey_slice) != 3 {\n\t\terr = fmt.Errorf(\"bad rrd cache key: %s\", ckey)\n\t\treturn\n\t}\n\n\tmd5 = ckey_slice[0]\n\tdsType = ckey_slice[1]\n\tstepInt64, err := strconv.ParseInt(ckey_slice[2], 10, 32)\n\tif err != nil {\n\t\treturn\n\t}\n\tstep = int(stepInt64)\n\n\t// return\n\terr = nil\n\treturn\n}\n\n// 判断是否为有效字符串(不包含指定字符和多字节字符)\nfunc IsValidString(str string) bool {\n\n\tr := []rune(str)\n\t// 允许多字节字符，这样可以保持继续支持中文counter\n\t// if len(r) != len(str) {\n\t// \treturn false\n\t// }\n\n\tfor _, t := range r {\n\t\tswitch t {\n\t\tcase '\\r':\n\t\t\treturn false\n\t\tcase '\\n':\n\t\t\treturn false\n\t\tcase '\\'':\n\t\t\treturn false\n\t\tcase '\"':\n\t\t\treturn false\n\t\tcase '>':\n\t\t\treturn false\n\t\tcase '\\032':\n\t\t\treturn false\n\t\tdefault:\n\t\t\t// 不可打印字符\n\t\t\tif !unicode.IsPrint(t) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "modules/graph/g/utils_test.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc Test_RrdFileName(t *testing.T) {\n\tif RrdFileName(\"/basedir\", \"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10) !=\n\t\tRrdFileName_orig(\"/basedir\", \"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10) {\n\t\tt.Error(\"not match with orig func\")\n\t}\n\n\tif RrdFileName(\"/basedir\", \"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10) !=\n\t\t\"/basedir/b0/b026324c6904b2a9cb4b88d6d61c81d1_GAUGE_10.rrd\" {\n\t\tt.Error(\"not match\")\n\t}\n}\n\nfunc Test_FormRrdCacheKey(t *testing.T) {\n\tif FormRrdCacheKey(\"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10) !=\n\t\tFormRrdCacheKey_orig(\"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10) {\n\t\tt.Error(\"not match\")\n\t}\n\n\tif FormRrdCacheKey(\"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10) !=\n\t\t\"b026324c6904b2a9cb4b88d6d61c81d1_GAUGE_10\" {\n\t\tt.Error(\"not match\")\n\t}\n}\n\nfunc Benchmark_RrdFileName(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tRrdFileName(\"/basedir\", \"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10)\n\t}\n}\n\nfunc Benchmark_RrdFileName_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tRrdFileName_orig(\"/basedir\", \"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10)\n\t}\n}\n\nfunc Benchmark_FormRrdCacheKey(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFormRrdCacheKey(\"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10)\n\t}\n}\n\nfunc Benchmark_FormRrdCacheKey_orig(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tFormRrdCacheKey_orig(\"b026324c6904b2a9cb4b88d6d61c81d1\", \"GAUGE\", 10)\n\t}\n}\n\nfunc RrdFileName_orig(baseDir string, md5 string, dsType string, step int) string {\n\treturn fmt.Sprintf(\"%s/%s/%s_%s_%d.rrd\", baseDir, md5[0:2], md5, dsType, step)\n}\n\nfunc FormRrdCacheKey_orig(md5 string, dsType string, step int) string {\n\treturn fmt.Sprintf(\"%s_%s_%d\", md5, dsType, step)\n}\n"
  },
  {
    "path": "modules/graph/http/common.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/store\"\n\t\"github.com/toolkits/file\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"strconv\"\n\t\"time\"\n)\n\nfunc configCommonRoutes() {\n\t// compatible with anteye\n\trouter.GET(\"/health\", func(c *gin.Context) {\n\t\tc.String(200, \"ok\")\n\t})\n\n\trouter.GET(\"/api/v2/health\", func(c *gin.Context) {\n\t\tJSONR(c, 200, gin.H{\"msg\": \"ok\"})\n\t})\n\n\trouter.GET(\"/api/v2/version\", func(c *gin.Context) {\n\t\tJSONR(c, 200, gin.H{\"value\": g.VersionMsg()})\n\t})\n\n\trouter.GET(\"/api/v2/workdir\", func(c *gin.Context) {\n\t\tJSONR(c, 200, gin.H{\"value\": file.SelfDir()})\n\t})\n\n\trouter.GET(\"/api/v2/config\", func(c *gin.Context) {\n\t\tJSONR(c, 200, gin.H{\"value\": g.Config()})\n\t})\n\n\trouter.POST(\"/api/v2/config/reload\", func(c *gin.Context) {\n\t\tg.ParseConfig(g.ConfigFile)\n\t\tJSONR(c, 200, gin.H{\"msg\": \"ok\"})\n\t})\n\n\trouter.GET(\"/api/v2/stats/graph-queue-size\", func(c *gin.Context) {\n\t\trt := make(map[string]int)\n\t\tfor i := 0; i < store.GraphItems.Size; i++ {\n\t\t\tkeys := store.GraphItems.KeysByIndex(i)\n\t\t\toneHourAgo := time.Now().Unix() - 3600\n\n\t\t\tcount := 0\n\t\t\tfor _, ckey := range keys {\n\t\t\t\titem := store.GraphItems.First(ckey)\n\t\t\t\tif item == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif item.Timestamp > oneHourAgo {\n\t\t\t\t\tcount++\n\t\t\t\t}\n\t\t\t}\n\t\t\ti_s := strconv.Itoa(i)\n\t\t\trt[i_s] = count\n\t\t}\n\t\tJSONR(c, 200, rt)\n\t})\n}\n"
  },
  {
    "path": "modules/graph/http/helper.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\ntype RespJson struct {\n\tError string `json:\"error,omitempty\"`\n\tMsg   string `json:\"message,omitempty\"`\n}\n\n// func JSONR(c *gin.Context, wcode int, msg interface{}) (werror error) {\nfunc JSONR(c *gin.Context, arg ...interface{}) (werror error) {\n\tvar (\n\t\twcode int\n\t\tmsg   interface{}\n\t)\n\n\tif len(arg) == 1 {\n\t\twcode = http.StatusOK\n\t\tmsg = arg[0]\n\t} else {\n\t\twcode = arg[0].(int)\n\t\tmsg = arg[1]\n\t}\n\n\tvar body interface{}\n\tif wcode == 200 {\n\t\tswitch msg.(type) {\n\t\tcase string:\n\t\t\tbody = RespJson{Msg: msg.(string)}\n\t\t\tc.JSON(http.StatusOK, body)\n\t\tdefault:\n\t\t\tc.JSON(http.StatusOK, msg)\n\t\t\tbody = msg\n\t\t}\n\t} else {\n\t\tswitch msg.(type) {\n\t\tcase string:\n\t\t\tbody = RespJson{Error: msg.(string)}\n\t\t\tc.JSON(wcode, body)\n\t\tcase error:\n\t\t\tbody = RespJson{Error: msg.(error).Error()}\n\t\t\tc.JSON(wcode, body)\n\t\tdefault:\n\t\t\tbody = RespJson{Error: \"system type error. please ask admin for help\"}\n\t\t\tc.JSON(wcode, body)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "modules/graph/http/http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"net\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n\t\"time\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/rrdtool\"\n)\n\ntype Dto struct {\n\tMsg  string      `json:\"msg\"`\n\tData interface{} `json:\"data\"`\n}\n\nvar Close_chan, Close_done_chan chan int\nvar router *gin.Engine\n\nfunc init() {\n\tClose_chan = make(chan int, 1)\n\tClose_done_chan = make(chan int, 1)\n\n}\n\nfunc RenderJson(w http.ResponseWriter, v interface{}) {\n\tbs, err := json.Marshal(v)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\tw.Write(bs)\n}\n\nfunc RenderDataJson(w http.ResponseWriter, data interface{}) {\n\tRenderJson(w, Dto{Msg: \"success\", Data: data})\n}\n\nfunc RenderMsgJson(w http.ResponseWriter, msg string) {\n\tRenderJson(w, map[string]string{\"msg\": msg})\n}\n\nfunc AutoRender(w http.ResponseWriter, data interface{}, err error) {\n\tif err != nil {\n\t\tRenderMsgJson(w, err.Error())\n\t\treturn\n\t}\n\tRenderDataJson(w, data)\n}\n\n// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted\n// connections. It's used by ListenAndServe and ListenAndServeTLS so\n// dead TCP connections (e.g. closing laptop mid-download) eventually\n// go away.\ntype TcpKeepAliveListener struct {\n\t*net.TCPListener\n}\n\nfunc (ln TcpKeepAliveListener) Accept() (c net.Conn, err error) {\n\ttc, err := ln.AcceptTCP()\n\tif err != nil {\n\t\treturn\n\t}\n\ttc.SetKeepAlive(true)\n\ttc.SetKeepAlivePeriod(3 * time.Minute)\n\treturn tc, nil\n}\n\nfunc Start() {\n\tif !g.Config().Http.Enabled {\n\t\tlog.Println(\"http.Start warning, not enabled\")\n\t\treturn\n\t}\n\n\tif !g.Config().Debug {\n\t\tgin.SetMode(gin.ReleaseMode)\n\t}\n\n\trouter = gin.Default()\n\n\tconfigCommonRoutes()\n\tconfigProcRoutes()\n\tconfigIndexRoutes()\n\n\trouter.GET(\"/api/v2/counter/migrate\", func(c *gin.Context) {\n\t\tcounter := rrdtool.GetCounterV2()\n\t\tlog.Debug(\"migrating counter v2:\", fmt.Sprintf(\"%+v\", counter))\n\t\tc.JSON(200, counter)\n\t})\n\n\t//compatible with open-falcon v0.1\n\trouter.GET(\"/counter/migrate\", func(c *gin.Context) {\n\t\tcnt := rrdtool.GetCounter()\n\t\tlog.Debug(\"migrating counter:\", cnt)\n\t\tc.JSON(200, gin.H{\"msg\": \"ok\", \"counter\": cnt})\n\t})\n\n\taddr := g.Config().Http.Listen\n\tif addr == \"\" {\n\t\treturn\n\t}\n\tgo router.Run(addr)\n\n\tselect {\n\tcase <-Close_chan:\n\t\tlog.Info(\"http recv sigout and exit...\")\n\t\tClose_done_chan <- 1\n\t\treturn\n\t}\n\n}\n"
  },
  {
    "path": "modules/graph/http/index.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/index\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc configIndexRoutes() {\n\t// 触发索引全量更新, 同步操作\n\trouter.GET(\"/index/updateAll\", func(c *gin.Context) {\n\t\tgo index.UpdateIndexAllByDefaultStep()\n\t\tJSONR(c, 200, gin.H{\"msg\": \"ok\"})\n\t})\n\n\t// 获取索引全量更新的并行数\n\trouter.GET(\"/index/updateAll/concurrent\", func(c *gin.Context) {\n\t\tJSONR(c, 200, gin.H{\"msg\": \"ok\", \"value\": index.GetConcurrentOfUpdateIndexAll()})\n\t})\n\n\ttype APIIndexItemInput struct {\n\t\tEndpoint string `json:\"endpoint\" form:\"endpoint\" binding:\"required\"`\n\t\tMetric   string `json:\"metric\" form:\"metric\" binding:\"required\"`\n\t\tStep     int    `json:\"step\" form:\"step\" binding:\"required\"`\n\t\tDstype   string `json:\"dstype\" form:\"dstype\" binding:\"required\"`\n\t\tTags     string `json:\"tags\" form:\"tags\"`\n\t}\n\n\t// 更新一条索引数据,用于手动建立索引 endpoint metric step dstype tags\n\trouter.POST(\"/api/v2/index\", func(c *gin.Context) {\n\t\tinputs := []*APIIndexItemInput{}\n\t\tif err := c.Bind(&inputs); err != nil {\n\t\t\tc.AbortWithError(500, err)\n\t\t\treturn\n\t\t}\n\n\t\tfor _, in := range inputs {\n\t\t\terr, tags := cutils.SplitTagsString(in.Tags)\n\t\t\tif err != nil {\n\t\t\t\tlog.Error(\"split tags:\", in.Tags, \"error:\", err)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr = index.UpdateIndexOne(in.Endpoint, in.Metric, tags, in.Dstype, in.Step)\n\t\t\tif err != nil {\n\t\t\t\tlog.Error(\"build index fail, item:\", in, \"error:\", err)\n\t\t\t} else {\n\t\t\t\tlog.Debug(\"build index manually\", in)\n\t\t\t}\n\t\t}\n\n\t\tJSONR(c, 200, gin.H{\"msg\": \"ok\"})\n\t})\n}\n"
  },
  {
    "path": "modules/graph/http/proc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/proc\"\n)\n\nfunc configProcRoutes() {\n\t// counter\n\trouter.GET(\"/counter/all\", func(c *gin.Context) {\n\t\tJSONR(c, 200, proc.GetAll())\n\t})\n\n\t// compatible with falcon task monitor\n\trouter.GET(\"/statistics/all\", func(c *gin.Context) {\n\t\tret := make(map[string]interface{})\n\t\tret[\"msg\"] = \"success\"\n\t\tret[\"data\"] = proc.GetAll()\n\t\tJSONR(c, 200, ret)\n\t})\n\n}\n"
  },
  {
    "path": "modules/graph/index/cache.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage index\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\ttcache \"github.com/toolkits/cache/localcache/timedcache\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/proc\"\n)\n\nconst (\n\tDefaultMaxCacheSize                     = 5000000 // 默认 最多500w个,太大了内存会耗尽\n\tDefaultCacheProcUpdateTaskSleepInterval = time.Duration(1) * time.Second\n)\n\n// item缓存\nvar (\n\tIndexedItemCache   = NewIndexCacheBase(DefaultMaxCacheSize)\n\tunIndexedItemCache = NewIndexCacheBase(DefaultMaxCacheSize)\n)\n\n// db本地缓存\nvar (\n\t// endpoint表的内存缓存, key:endpoint(string) / value:id(int64)\n\tdbEndpointCache = tcache.New(600*time.Second, 60*time.Second)\n\t// endpoint_counter表的内存缓存, key:endpoint_id-counter(string) / val:dstype-step(string)\n\tdbEndpointCounterCache = tcache.New(600*time.Second, 60*time.Second)\n)\n\n// 初始化cache\nfunc InitCache() {\n\tgo startCacheProcUpdateTask()\n}\n\n// USED WHEN QUERY\nfunc GetTypeAndStep(endpoint string, counter string) (dsType string, step int, found bool) {\n\t// get it from index cache\n\tpk := cutils.Md5(fmt.Sprintf(\"%s/%s\", endpoint, counter))\n\tif icitem := IndexedItemCache.Get(pk); icitem != nil {\n\t\tif item := icitem.(*IndexCacheItem).Item; item != nil {\n\t\t\tdsType = item.DsType\n\t\t\tstep = item.Step\n\t\t\tfound = true\n\t\t\treturn\n\t\t}\n\t}\n\n\t// statistics\n\tproc.GraphLoadDbCnt.Incr()\n\n\t// get it from db, this should rarely happen\n\tvar endpointId int64 = -1\n\tif endpointId, found = GetEndpointFromCache(endpoint); found {\n\t\tif dsType, step, found = GetCounterFromCache(endpointId, counter); found {\n\t\t\t//found = true\n\t\t\treturn\n\t\t}\n\t}\n\n\t// do not find it, this must be a bad request\n\tfound = false\n\treturn\n}\n\n// Return EndpointId if Found\nfunc GetEndpointFromCache(endpoint string) (int64, bool) {\n\t// get from cache\n\tendpointId, found := dbEndpointCache.Get(endpoint)\n\tif found {\n\t\treturn endpointId.(int64), true\n\t}\n\n\t// get from db\n\tvar id int64 = -1\n\terr := g.DB.QueryRow(\"SELECT id FROM endpoint WHERE endpoint = ?\", endpoint).Scan(&id)\n\tif err != nil && err != sql.ErrNoRows {\n\t\tlog.Println(\"query endpoint id fail,\", err)\n\t\treturn -1, false\n\t}\n\n\tif err == sql.ErrNoRows || id < 0 {\n\t\treturn -1, false\n\t}\n\n\t// update cache\n\tdbEndpointCache.Set(endpoint, id, 0)\n\n\treturn id, true\n}\n\n// Return DsType Step if Found\nfunc GetCounterFromCache(endpointId int64, counter string) (dsType string, step int, found bool) {\n\tvar err error\n\t// get from cache\n\tkey := fmt.Sprintf(\"%d-%s\", endpointId, counter)\n\tdsTypeStep, found := dbEndpointCounterCache.Get(key)\n\tif found {\n\t\tarr := strings.Split(dsTypeStep.(string), \"_\")\n\t\tstep, err = strconv.Atoi(arr[1])\n\t\tif err != nil {\n\t\t\tfound = false\n\t\t\treturn\n\t\t}\n\t\tdsType = arr[0]\n\t\treturn\n\t}\n\n\t// get from db\n\terr = g.DB.QueryRow(\"SELECT type, step FROM endpoint_counter WHERE endpoint_id = ? and counter = ?\",\n\t\tendpointId, counter).Scan(&dsType, &step)\n\tif err != nil && err != sql.ErrNoRows {\n\t\tlog.Println(\"query type and step fail\", err)\n\t\treturn\n\t}\n\n\tif err == sql.ErrNoRows {\n\t\treturn\n\t}\n\n\t// update cache\n\tdbEndpointCounterCache.Set(key, fmt.Sprintf(\"%s_%d\", dsType, step), 0)\n\n\tfound = true\n\treturn\n}\n\n// 更新 cache的统计信息\nfunc startCacheProcUpdateTask() {\n\tfor {\n\t\ttime.Sleep(DefaultCacheProcUpdateTaskSleepInterval)\n\t\tproc.IndexedItemCacheCnt.SetCnt(int64(IndexedItemCache.Size()))\n\t\tproc.UnIndexedItemCacheCnt.SetCnt(int64(unIndexedItemCache.Size()))\n\t\tproc.EndpointCacheCnt.SetCnt(int64(dbEndpointCache.Size()))\n\t\tproc.CounterCacheCnt.SetCnt(int64(dbEndpointCounterCache.Size()))\n\t}\n}\n\n// INDEX CACHE\n// 索引缓存的元素数据结构\ntype IndexCacheItem struct {\n\tUUID string\n\tItem *cmodel.GraphItem\n}\n\nfunc NewIndexCacheItem(uuid string, item *cmodel.GraphItem) *IndexCacheItem {\n\treturn &IndexCacheItem{UUID: uuid, Item: item}\n}\n\n// 索引缓存-基本缓存容器\ntype IndexCacheBase struct {\n\tsync.RWMutex\n\tmaxSize int\n\tdata    map[string]interface{}\n}\n\nfunc NewIndexCacheBase(max int) *IndexCacheBase {\n\treturn &IndexCacheBase{maxSize: max, data: make(map[string]interface{})}\n}\n\nfunc (this *IndexCacheBase) GetMaxSize() int {\n\treturn this.maxSize\n}\n\nfunc (this *IndexCacheBase) Put(key string, item interface{}) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.data[key] = item\n}\n\nfunc (this *IndexCacheBase) Remove(key string) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tdelete(this.data, key)\n}\n\nfunc (this *IndexCacheBase) Get(key string) interface{} {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.data[key]\n}\n\nfunc (this *IndexCacheBase) ContainsKey(key string) bool {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.data[key] != nil\n}\n\nfunc (this *IndexCacheBase) Size() int {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn len(this.data)\n}\n\nfunc (this *IndexCacheBase) Keys() []string {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\n\tcount := len(this.data)\n\tif count == 0 {\n\t\treturn []string{}\n\t}\n\n\tkeys := make([]string, 0, count)\n\tfor key := range this.data {\n\t\tkeys = append(keys, key)\n\t}\n\n\treturn keys\n}\n"
  },
  {
    "path": "modules/graph/index/index.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage index\n\nimport (\n\tlog \"github.com/sirupsen/logrus\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/store\"\n\t\"github.com/toolkits/file\"\n)\n\n// 初始化索引功能模块\nfunc Start() {\n\tInitCache()\n\tgo StartIndexUpdateIncrTask()\n\tlog.Debug(\"index.Start ok\")\n}\n\n// index收到一条新上报的监控数据,尝试用于增量更新索引\nfunc ReceiveItem(item *cmodel.GraphItem, md5 string) {\n\tif item == nil {\n\t\treturn\n\t}\n\n\tuuid := item.UUID()\n\n\t// 已上报过的数据\n\tif IndexedItemCache.ContainsKey(md5) {\n\t\told := IndexedItemCache.Get(md5).(*IndexCacheItem)\n\t\tif uuid == old.UUID { // dsType+step没有发生变化,只更新缓存\n\t\t\tIndexedItemCache.Put(md5, NewIndexCacheItem(uuid, item))\n\t\t} else { // dsType+step变化了,当成一个新的增量来处理\n\t\t\tunIndexedItemCache.Put(md5, NewIndexCacheItem(uuid, item))\n\t\t}\n\t\treturn\n\t}\n\n\t// 针对 mysql索引重建场景 做的优化，是否有rrdtool文件存在,如果有 则认为MySQL中已建立索引；\n\trrdFileName := g.RrdFileName(g.Config().RRD.Storage, md5, item.DsType, item.Step)\n\tif g.IsRrdFileExist(rrdFileName) {\n\t\tIndexedItemCache.Put(md5, NewIndexCacheItem(uuid, item))\n\t\treturn\n\t}\n\n\t// 缓存未命中, 放入增量更新队列\n\tunIndexedItemCache.Put(md5, NewIndexCacheItem(uuid, item))\n}\n\n//从graph cache中删除掉某个item, 并删除指定的counter对应的rrd文件\nfunc RemoveItem(item *cmodel.GraphItem) {\n\tmd5 := item.Checksum()\n\tIndexedItemCache.Remove(md5)\n\tunIndexedItemCache.Remove(md5)\n\n\t//discard data of memory\n\tchecksum := item.Checksum()\n\tkey := g.FormRrdCacheKey(checksum, item.DsType, item.Step)\n\tpoped_items := store.GraphItems.PopAll(key)\n\tlog.Debugf(\"discard data of item:%v, size:%d\", item, len(poped_items))\n\n\trrdFileName := g.RrdFileName(g.Config().RRD.Storage, md5, item.DsType, item.Step)\n\tfile.Remove(rrdFileName)\n\tlog.Debug(\"remove rrdfile:\", rrdFileName)\n}\n"
  },
  {
    "path": "modules/graph/index/index_update_all_task.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage index\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"time\"\n\n\tnsema \"github.com/toolkits/concurrent/semaphore\"\n\tntime \"github.com/toolkits/time\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\tproc \"github.com/open-falcon/falcon-plus/modules/graph/proc\"\n)\n\nconst (\n\tDefaultUpdateStepInSec     = 2 * 24 * 3600 //更新步长,一定不能大于删除步长. 两天内的数据,都可以用来建立索引\n\tConcurrentOfUpdateIndexAll = 1\n)\n\nvar (\n\tsemaIndexUpdateAllTask = nsema.NewSemaphore(ConcurrentOfUpdateIndexAll) //全量同步任务 并发控制器\n\tsemaIndexUpdateAll     = nsema.NewSemaphore(4)                          // 索引全量更新时的mysql操作并发控制\n)\n\n// 索引全量更新的当前并行数\nfunc GetConcurrentOfUpdateIndexAll() int {\n\treturn ConcurrentOfUpdateIndexAll - semaIndexUpdateAllTask.AvailablePermits()\n}\n\n// 索引的全量更新\nfunc UpdateIndexAllByDefaultStep() {\n\tUpdateIndexAll(DefaultUpdateStepInSec)\n}\nfunc UpdateIndexAll(updateStepInSec int64) {\n\t// 减少任务积压,但高并发时可能无效(AvailablePermits不是线程安全的)\n\tif semaIndexUpdateAllTask.AvailablePermits() <= 0 {\n\t\tlog.Println(\"updateIndexAll, concurrent not available\")\n\t\treturn\n\t}\n\n\tsemaIndexUpdateAllTask.Acquire()\n\tdefer semaIndexUpdateAllTask.Release()\n\n\tstartTs := time.Now().Unix()\n\tcnt := updateIndexAll(updateStepInSec)\n\tendTs := time.Now().Unix()\n\tlog.Printf(\"UpdateIndexAll, lastStartTs %s, updateStepInSec %d, lastTimeConsumingInSec %d\\n\",\n\t\tntime.FormatTs(startTs), updateStepInSec, endTs-startTs)\n\n\t// statistics\n\tproc.IndexUpdateAllCnt.SetCnt(int64(cnt))\n\tproc.IndexUpdateAll.Incr()\n\tproc.IndexUpdateAll.PutOther(\"lastStartTs\", ntime.FormatTs(startTs))\n\tproc.IndexUpdateAll.PutOther(\"updateStepInSec\", updateStepInSec)\n\tproc.IndexUpdateAll.PutOther(\"lastTimeConsumingInSec\", endTs-startTs)\n\tproc.IndexUpdateAll.PutOther(\"updateCnt\", cnt)\n}\n\n// 更新一条监控数据对应的索引. 用于手动添加索引,一般情况下不会使用\nfunc UpdateIndexOne(endpoint string, metric string, tags map[string]string, dstype string, step int) error {\n\titemDemo := &cmodel.GraphItem{\n\t\tEndpoint: endpoint,\n\t\tMetric:   metric,\n\t\tTags:     tags,\n\t\tDsType:   dstype,\n\t\tStep:     step,\n\t}\n\tmd5 := itemDemo.Checksum()\n\tuuid := itemDemo.UUID()\n\n\tcached := IndexedItemCache.Get(md5)\n\tif cached == nil {\n\t\treturn fmt.Errorf(\"not found\")\n\t}\n\n\ticitem := cached.(*IndexCacheItem)\n\tif icitem.UUID != uuid {\n\t\treturn fmt.Errorf(\"bad type or step\")\n\t}\n\tgitem := icitem.Item\n\n\tdbConn, err := g.GetDbConn(\"UpdateIndexIncrTask\")\n\tif err != nil {\n\t\tlog.Println(\"[ERROR] make dbConn fail\", err)\n\t\treturn err\n\t}\n\n\treturn updateIndexFromOneItem(gitem, dbConn)\n}\n\nfunc updateIndexAll(updateStepInSec int64) int {\n\tvar ret int = 0\n\tif IndexedItemCache == nil || IndexedItemCache.Size() <= 0 {\n\t\treturn ret\n\t}\n\n\tdbConn, err := g.GetDbConn(\"UpdateIndexIncrTask\")\n\tif err != nil {\n\t\tlog.Println(\"[ERROR] make dbConn fail\", err)\n\t\treturn ret\n\t}\n\n\t// lastTs for update index\n\tts := time.Now().Unix()\n\tlastTs := ts - updateStepInSec\n\n\tkeys := IndexedItemCache.Keys()\n\tfor _, key := range keys {\n\t\ticitem := IndexedItemCache.Get(key)\n\t\tif icitem == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tgitem := icitem.(*IndexCacheItem).Item\n\t\tif gitem.Timestamp < lastTs { //缓存中的数据太旧了,不能用于索引的全量更新\n\t\t\tIndexedItemCache.Remove(key) //在这里做个删除,有点恶心\n\t\t\tcontinue\n\t\t}\n\t\t// 并发写mysql\n\t\tsemaIndexUpdateAll.Acquire()\n\t\tgo func(gitem *cmodel.GraphItem, dbConn *sql.DB) {\n\t\t\tdefer semaIndexUpdateAll.Release()\n\t\t\terr := updateIndexFromOneItem(gitem, dbConn)\n\t\t\tif err != nil {\n\t\t\t\tproc.IndexUpdateAllErrorCnt.Incr()\n\t\t\t}\n\t\t}(gitem, dbConn)\n\n\t\tret++\n\t}\n\n\treturn ret\n}\n\n// 根据item,更新mysql\nfunc updateIndexFromOneItem(item *cmodel.GraphItem, conn *sql.DB) error {\n\tif item == nil {\n\t\treturn nil\n\t}\n\n\tts := item.Timestamp\n\tvar endpointId int64 = -1\n\n\t// endpoint表\n\tsqlStr := `INSERT INTO endpoint(endpoint, ts, t_create)\n\t\tVALUES (?, ?, NOW())\n\t\tON DUPLICATE KEY UPDATE ts=?, t_modify=NOW()`\n\n\t_, err := conn.Exec(sqlStr, item.Endpoint, ts, ts)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn err\n\t}\n\tproc.IndexUpdateIncrDbEndpointInsertCnt.Incr()\n\n\terr = conn.QueryRow(\"SELECT id FROM endpoint WHERE endpoint = ?\", item.Endpoint).Scan(&endpointId)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn err\n\t}\n\tif endpointId <= 0 {\n\t\tlog.Errorf(\"no such endpoint in db, endpoint=%s\", item.Endpoint)\n\t\treturn errors.New(\"no such endpoint\")\n\t}\n\n\t// tag_endpoint表\n\tfor tagKey, tagVal := range item.Tags {\n\t\ttag := fmt.Sprintf(\"%s=%s\", tagKey, tagVal)\n\t\tsqlStr := `INSERT INTO tag_endpoint(tag, endpoint_id, ts, t_create)\n\t\t\tVALUES (?, ?, ?, NOW())\n\t\t\tON DUPLICATE KEY UPDATE ts=?, t_modify=NOW()`\n\n\t\t_, err := conn.Exec(sqlStr, tag, endpointId, ts, ts)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\treturn err\n\t\t}\n\t\tproc.IndexUpdateIncrDbTagEndpointInsertCnt.Incr()\n\t}\n\n\t// endpoint_counter表\n\tcounter := item.Metric\n\tif len(item.Tags) > 0 {\n\t\tcounter = fmt.Sprintf(\"%s/%s\", counter, cutils.SortedTags(item.Tags))\n\t}\n\n\tsqlStr = `INSERT INTO endpoint_counter(endpoint_id,counter,step,type,ts,t_create)\n\t\tVALUES (?,?,?,?,?,NOW())\n\t\tON DUPLICATE KEY UPDATE ts=?,step=?,type=?,t_modify=NOW()`\n\n\t_, err = conn.Exec(sqlStr, endpointId, counter, item.Step, item.DsType, ts, ts, item.Step, item.DsType)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn err\n\t}\n\tproc.IndexUpdateIncrDbEndpointCounterInsertCnt.Incr()\n\n\treturn nil\n}\n"
  },
  {
    "path": "modules/graph/index/index_update_incr_task.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage index\n\nimport (\n\t\"database/sql\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"time\"\n\n\tnsema \"github.com/toolkits/concurrent/semaphore\"\n\tntime \"github.com/toolkits/time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\tproc \"github.com/open-falcon/falcon-plus/modules/graph/proc\"\n)\n\nconst (\n\tIndexUpdateIncrTaskSleepInterval = time.Duration(1) * time.Second // 增量更新间隔时间, 默认30s\n)\n\nvar (\n\tsemaUpdateIndexIncr = nsema.NewSemaphore(2) // 索引增量更新时操作mysql的并发控制\n)\n\n// 启动索引的 异步、增量更新 任务, 每隔一定时间，刷新cache中的数据到数据库中\nfunc StartIndexUpdateIncrTask() {\n\tfor {\n\t\ttime.Sleep(IndexUpdateIncrTaskSleepInterval)\n\t\tstartTs := time.Now().Unix()\n\t\tcnt := updateIndexIncr()\n\t\tendTs := time.Now().Unix()\n\t\t// statistics\n\t\tproc.IndexUpdateIncrCnt.SetCnt(int64(cnt))\n\t\tproc.IndexUpdateIncr.Incr()\n\t\tproc.IndexUpdateIncr.PutOther(\"lastStartTs\", ntime.FormatTs(startTs))\n\t\tproc.IndexUpdateIncr.PutOther(\"lastTimeConsumingInSec\", endTs-startTs)\n\t}\n}\n\n// 进行一次增量更新\nfunc updateIndexIncr() int {\n\tret := 0\n\tif unIndexedItemCache == nil || unIndexedItemCache.Size() <= 0 {\n\t\treturn ret\n\t}\n\n\tdbConn, err := g.GetDbConn(\"UpdateIndexIncrTask\")\n\tif err != nil {\n\t\tlog.Error(\"[ERROR] get dbConn fail\", err)\n\t\treturn ret\n\t}\n\n\tkeys := unIndexedItemCache.Keys()\n\tfor _, key := range keys {\n\t\ticitem := unIndexedItemCache.Get(key)\n\t\tunIndexedItemCache.Remove(key)\n\t\tif icitem != nil {\n\t\t\t// 并发更新mysql\n\t\t\tsemaUpdateIndexIncr.Acquire()\n\t\t\tgo func(key string, icitem *IndexCacheItem, dbConn *sql.DB) {\n\t\t\t\tdefer semaUpdateIndexIncr.Release()\n\t\t\t\terr := updateIndexFromOneItem(icitem.Item, dbConn)\n\t\t\t\tif err != nil {\n\t\t\t\t\tproc.IndexUpdateIncrErrorCnt.Incr()\n\t\t\t\t} else {\n\t\t\t\t\tIndexedItemCache.Put(key, icitem)\n\t\t\t\t}\n\t\t\t}(key, icitem.(*IndexCacheItem), dbConn)\n\t\t\tret++\n\t\t}\n\t}\n\n\treturn ret\n}\n"
  },
  {
    "path": "modules/graph/main.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/graph/api\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/cron\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/http\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/index\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/rrdtool\"\n)\n\nfunc start_signal(pid int, cfg *g.GlobalConfig) {\n\tsigs := make(chan os.Signal, 1)\n\tlog.Println(pid, \"register signal notify\")\n\tsignal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)\n\n\tfor {\n\t\ts := <-sigs\n\t\tlog.Println(\"recv\", s)\n\n\t\tswitch s {\n\t\tcase syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:\n\t\t\tlog.Println(\"graceful shut down\")\n\t\t\tif cfg.Http.Enabled {\n\t\t\t\thttp.Close_chan <- 1\n\t\t\t\t<-http.Close_done_chan\n\t\t\t}\n\t\t\tlog.Println(\"http stop ok\")\n\n\t\t\tif cfg.Rpc.Enabled {\n\t\t\t\tapi.Close_chan <- 1\n\t\t\t\t<-api.Close_done_chan\n\t\t\t}\n\t\t\tlog.Println(\"rpc stop ok\")\n\n\t\t\trrdtool.Out_done_chan <- 1\n\t\t\trrdtool.FlushAll(true)\n\t\t\tlog.Println(\"rrdtool stop ok\")\n\n\t\t\tlog.Println(pid, \"exit\")\n\t\t\tos.Exit(0)\n\t\t}\n\t}\n}\n\nfunc main() {\n\tg.BinaryName = BinaryName\n\tg.Version = Version\n\tg.GitCommit = GitCommit\n\n\tcfg := flag.String(\"c\", \"cfg.json\", \"specify config file\")\n\tversion := flag.Bool(\"v\", false, \"show version\")\n\tversionGit := flag.Bool(\"vg\", false, \"show version and git commit log\")\n\tflag.Parse()\n\n\tif *version {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\tif *versionGit {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\n\t// global config\n\tg.ParseConfig(*cfg)\n\n\tif g.Config().Debug {\n\t\tg.InitLog(\"debug\")\n\t} else {\n\t\tg.InitLog(\"info\")\n\t}\n\n\t// init db\n\tg.InitDB()\n\t// rrdtool init\n\trrdtool.InitChannel()\n\t// rrdtool before api for disable loopback connection\n\trrdtool.Start()\n\t// start api\n\tgo api.Start()\n\t// start indexing\n\tindex.Start()\n\t// start http server\n\tgo http.Start()\n\tgo cron.CleanCache()\n\n\tstart_signal(os.Getpid(), g.Config())\n}\n"
  },
  {
    "path": "modules/graph/proc/proc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage proc\n\nimport (\n\tnproc \"github.com/toolkits/proc\"\n)\n\n// 索引增量更新\nvar (\n\tIndexUpdateIncr         = nproc.NewSCounterQps(\"IndexUpdateIncr\")\n\tIndexUpdateIncrCnt      = nproc.NewSCounterBase(\"IndexUpdateIncrCnt\")\n\tIndexUpdateIncrErrorCnt = nproc.NewSCounterQps(\"IndexUpdateIncrErrorCnt\")\n\n\tIndexUpdateIncrDbEndpointSelectCnt = nproc.NewSCounterQps(\"IndexUpdateIncrDbEndpointSelectCnt\")\n\tIndexUpdateIncrDbEndpointInsertCnt = nproc.NewSCounterQps(\"IndexUpdateIncrDbEndpointInsertCnt\")\n\n\tIndexUpdateIncrDbTagEndpointSelectCnt = nproc.NewSCounterQps(\"IndexUpdateIncrDbTagEndpointSelectCnt\")\n\tIndexUpdateIncrDbTagEndpointInsertCnt = nproc.NewSCounterQps(\"IndexUpdateIncrDbTagEndpointInsertCnt\")\n\n\tIndexUpdateIncrDbEndpointCounterSelectCnt = nproc.NewSCounterQps(\"IndexUpdateIncrDbEndpointCounterSelectCnt\")\n\tIndexUpdateIncrDbEndpointCounterInsertCnt = nproc.NewSCounterQps(\"IndexUpdateIncrDbEndpointCounterInsertCnt\")\n\tIndexUpdateIncrDbEndpointCounterUpdateCnt = nproc.NewSCounterQps(\"IndexUpdateIncrDbEndpointCounterUpdateCnt\")\n)\n\n// 索引全量更新\nvar (\n\tIndexUpdateAll         = nproc.NewSCounterQps(\"IndexUpdateAll\")\n\tIndexUpdateAllCnt      = nproc.NewSCounterBase(\"IndexUpdateAllCnt\")\n\tIndexUpdateAllErrorCnt = nproc.NewSCounterQps(\"IndexUpdateAllErrorCnt\")\n)\n\n// 索引缓存大小\nvar (\n\tIndexedItemCacheCnt   = nproc.NewSCounterBase(\"IndexedItemCacheCnt\")\n\tUnIndexedItemCacheCnt = nproc.NewSCounterBase(\"UnIndexedItemCacheCnt\")\n\tEndpointCacheCnt      = nproc.NewSCounterBase(\"EndpointCacheCnt\")\n\tCounterCacheCnt       = nproc.NewSCounterBase(\"CounterCacheCnt\")\n)\n\n// Rpc\nvar (\n\tGraphRpcRecvCnt = nproc.NewSCounterQps(\"GraphRpcRecvCnt\")\n)\n\n// Query\nvar (\n\tGraphQueryCnt     = nproc.NewSCounterQps(\"GraphQueryCnt\")\n\tGraphQueryItemCnt = nproc.NewSCounterQps(\"GraphQueryItemCnt\")\n\tGraphInfoCnt      = nproc.NewSCounterQps(\"GraphInfoCnt\")\n\tGraphLastCnt      = nproc.NewSCounterQps(\"GraphLastCnt\")\n\tGraphLastRawCnt   = nproc.NewSCounterQps(\"GraphLastRawCnt\")\n\tGraphLoadDbCnt    = nproc.NewSCounterQps(\"GraphLoadDbCnt\") // load sth from db when query/info, tmp\n)\n\nfunc GetAll() []interface{} {\n\tret := make([]interface{}, 0)\n\n\t// rpc recv\n\tret = append(ret, GraphRpcRecvCnt.Get())\n\n\t// query\n\tret = append(ret, GraphQueryCnt.Get())\n\tret = append(ret, GraphQueryItemCnt.Get())\n\tret = append(ret, GraphInfoCnt.Get())\n\tret = append(ret, GraphLastCnt.Get())\n\tret = append(ret, GraphLastRawCnt.Get())\n\tret = append(ret, GraphLoadDbCnt.Get())\n\n\t// index update all\n\tret = append(ret, IndexUpdateAll.Get())\n\tret = append(ret, IndexUpdateAllCnt.Get())\n\tret = append(ret, IndexUpdateAllErrorCnt.Get())\n\n\t// index update incr\n\tret = append(ret, IndexUpdateIncr.Get())\n\tret = append(ret, IndexUpdateIncrCnt.Get())\n\tret = append(ret, IndexUpdateIncrErrorCnt.Get())\n\n\tret = append(ret, IndexUpdateIncrDbEndpointSelectCnt.Get())\n\tret = append(ret, IndexUpdateIncrDbEndpointInsertCnt.Get())\n\n\tret = append(ret, IndexUpdateIncrDbTagEndpointSelectCnt.Get())\n\tret = append(ret, IndexUpdateIncrDbTagEndpointInsertCnt.Get())\n\n\tret = append(ret, IndexUpdateIncrDbEndpointCounterSelectCnt.Get())\n\tret = append(ret, IndexUpdateIncrDbEndpointCounterInsertCnt.Get())\n\tret = append(ret, IndexUpdateIncrDbEndpointCounterUpdateCnt.Get())\n\n\t// index db cache\n\tret = append(ret, IndexedItemCacheCnt.Get())\n\tret = append(ret, UnIndexedItemCacheCnt.Get())\n\tret = append(ret, EndpointCacheCnt.Get())\n\tret = append(ret, CounterCacheCnt.Get())\n\n\treturn ret\n}\n"
  },
  {
    "path": "modules/graph/rrdtool/migrate.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rrdtool\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/rpc\"\n\t\"os\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\tpfc \"github.com/niean/goperfcounter\"\n\t\"github.com/toolkits/consistent\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/store\"\n)\n\nconst (\n\t_ = iota\n\tNET_TASK_M_SEND\n\tNET_TASK_M_QUERY\n\tNET_TASK_M_PULL\n)\n\ntype Net_task_t struct {\n\tMethod int\n\tKey    string\n\tDone   chan error\n\tArgs   interface{}\n\tReply  interface{}\n}\n\nconst (\n\tFETCH_S_SUCCESS = iota\n\tFETCH_S_ERR\n\tFETCH_S_ISNOTEXIST\n\tSEND_S_SUCCESS\n\tSEND_S_ERR\n\tQUERY_S_SUCCESS\n\tQUERY_S_ERR\n\tCONN_S_ERR\n\tCONN_S_DIAL\n\tSTAT_SIZE\n)\n\nvar (\n\tConsistent       *consistent.Consistent\n\tNet_task_ch      map[string]chan *Net_task_t\n\tclients          map[string][]*rpc.Client\n\tflushrrd_timeout int32\n\tstat_cnt         [STAT_SIZE]uint64\n)\n\ntype MigrateCounter struct {\n\tFetchSuccess  uint64\n\tFetchErr      uint64\n\tFetchNotExist uint64\n\tSendSuccess   uint64\n\tSendErr       uint64\n\tQuerySuccess  uint64\n\tQueryErr      uint64\n\tConnErr       uint64\n\tConnDial      uint64\n}\n\nfunc init() {\n\tConsistent = consistent.New()\n\tNet_task_ch = make(map[string]chan *Net_task_t)\n\tclients = make(map[string][]*rpc.Client)\n}\n\nfunc GetCounterV2() *MigrateCounter {\n\treturn &MigrateCounter{\n\t\tFetchSuccess:  atomic.LoadUint64(&stat_cnt[FETCH_S_SUCCESS]),\n\t\tFetchErr:      atomic.LoadUint64(&stat_cnt[FETCH_S_ERR]),\n\t\tFetchNotExist: atomic.LoadUint64(&stat_cnt[FETCH_S_ISNOTEXIST]),\n\t\tSendSuccess:   atomic.LoadUint64(&stat_cnt[SEND_S_SUCCESS]),\n\t\tSendErr:       atomic.LoadUint64(&stat_cnt[SEND_S_ERR]),\n\t\tQuerySuccess:  atomic.LoadUint64(&stat_cnt[QUERY_S_SUCCESS]),\n\t\tQueryErr:      atomic.LoadUint64(&stat_cnt[QUERY_S_ERR]),\n\t\tConnErr:       atomic.LoadUint64(&stat_cnt[CONN_S_ERR]),\n\t\tConnDial:      atomic.LoadUint64(&stat_cnt[CONN_S_DIAL]),\n\t}\n}\n\nfunc GetCounter() (ret string) {\n\treturn fmt.Sprintf(\"FETCH_S_SUCCESS[%d] FETCH_S_ERR[%d] FETCH_S_ISNOTEXIST[%d] SEND_S_SUCCESS[%d] SEND_S_ERR[%d] QUERY_S_SUCCESS[%d] QUERY_S_ERR[%d] CONN_S_ERR[%d] CONN_S_DIAL[%d]\",\n\t\tatomic.LoadUint64(&stat_cnt[FETCH_S_SUCCESS]),\n\t\tatomic.LoadUint64(&stat_cnt[FETCH_S_ERR]),\n\t\tatomic.LoadUint64(&stat_cnt[FETCH_S_ISNOTEXIST]),\n\t\tatomic.LoadUint64(&stat_cnt[SEND_S_SUCCESS]),\n\t\tatomic.LoadUint64(&stat_cnt[SEND_S_ERR]),\n\t\tatomic.LoadUint64(&stat_cnt[QUERY_S_SUCCESS]),\n\t\tatomic.LoadUint64(&stat_cnt[QUERY_S_ERR]),\n\t\tatomic.LoadUint64(&stat_cnt[CONN_S_ERR]),\n\t\tatomic.LoadUint64(&stat_cnt[CONN_S_DIAL]))\n}\n\nfunc dial(address string, timeout time.Duration) (*rpc.Client, error) {\n\td := net.Dialer{Timeout: timeout}\n\tconn, err := d.Dial(\"tcp\", address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif tc, ok := conn.(*net.TCPConn); ok {\n\t\tif err := tc.SetKeepAlive(true); err != nil {\n\t\t\tconn.Close()\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn rpc.NewClient(conn), err\n}\n\nfunc migrate_start(cfg *g.GlobalConfig) {\n\tvar err error\n\tvar i int\n\tif cfg.Migrate.Enabled {\n\t\tConsistent.NumberOfReplicas = cfg.Migrate.Replicas\n\n\t\tnodes := cutils.KeysOfMap(cfg.Migrate.Cluster)\n\t\tfor _, node := range nodes {\n\t\t\taddr := cfg.Migrate.Cluster[node]\n\t\t\tConsistent.Add(node)\n\t\t\tNet_task_ch[node] = make(chan *Net_task_t, 16)\n\t\t\tclients[node] = make([]*rpc.Client, cfg.Migrate.Concurrency)\n\n\t\t\tfor i = 0; i < cfg.Migrate.Concurrency; i++ {\n\t\t\t\tif clients[node][i], err = dial(addr, time.Second); err != nil {\n\t\t\t\t\tlog.Fatalf(\"node:%s addr:%s err:%s\\n\", node, addr, err)\n\t\t\t\t}\n\t\t\t\tgo net_task_worker(i, Net_task_ch[node], &clients[node][i], addr)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc net_task_worker(idx int, ch chan *Net_task_t, client **rpc.Client, addr string) {\n\tvar err error\n\tfor {\n\t\tselect {\n\t\tcase task := <-ch:\n\t\t\tif task.Method == NET_TASK_M_SEND {\n\t\t\t\tif err = send_data(client, task.Key, addr); err != nil {\n\t\t\t\t\tpfc.Meter(\"migrate.send.err\", 1)\n\t\t\t\t\tatomic.AddUint64(&stat_cnt[SEND_S_ERR], 1)\n\t\t\t\t} else {\n\t\t\t\t\tpfc.Meter(\"migrate.send.ok\", 1)\n\t\t\t\t\tatomic.AddUint64(&stat_cnt[SEND_S_SUCCESS], 1)\n\t\t\t\t}\n\t\t\t} else if task.Method == NET_TASK_M_QUERY {\n\t\t\t\tif err = query_data(client, addr, task.Args, task.Reply); err != nil {\n\t\t\t\t\tpfc.Meter(\"migrate.query.err\", 1)\n\t\t\t\t\tatomic.AddUint64(&stat_cnt[QUERY_S_ERR], 1)\n\t\t\t\t} else {\n\t\t\t\t\tpfc.Meter(\"migrate.query.ok\", 1)\n\t\t\t\t\tatomic.AddUint64(&stat_cnt[QUERY_S_SUCCESS], 1)\n\t\t\t\t}\n\t\t\t} else if task.Method == NET_TASK_M_PULL {\n\t\t\t\tif atomic.LoadInt32(&flushrrd_timeout) != 0 {\n\t\t\t\t\t// hope this more faster than fetch_rrd\n\t\t\t\t\tif err = send_data(client, task.Key, addr); err != nil {\n\t\t\t\t\t\tpfc.Meter(\"migrate.sendbusy.err\", 1)\n\t\t\t\t\t\tatomic.AddUint64(&stat_cnt[SEND_S_ERR], 1)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpfc.Meter(\"migrate.sendbusy.ok\", 1)\n\t\t\t\t\t\tatomic.AddUint64(&stat_cnt[SEND_S_SUCCESS], 1)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif err = fetch_rrd(client, task.Key, addr); err != nil {\n\t\t\t\t\t\tif os.IsNotExist(err) {\n\t\t\t\t\t\t\tpfc.Meter(\"migrate.scprrd.null\", 1)\n\t\t\t\t\t\t\t//文件不存在时，直接将缓存数据刷入本地\n\t\t\t\t\t\t\tatomic.AddUint64(&stat_cnt[FETCH_S_ISNOTEXIST], 1)\n\t\t\t\t\t\t\tstore.GraphItems.SetFlag(task.Key, 0)\n\t\t\t\t\t\t\tCommitByKey(task.Key)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpfc.Meter(\"migrate.scprrd.err\", 1)\n\t\t\t\t\t\t\t//warning:其他异常情况，缓存数据会堆积\n\t\t\t\t\t\t\tatomic.AddUint64(&stat_cnt[FETCH_S_ERR], 1)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpfc.Meter(\"migrate.scprrd.ok\", 1)\n\t\t\t\t\t\tatomic.AddUint64(&stat_cnt[FETCH_S_SUCCESS], 1)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\terr = errors.New(\"error net task method\")\n\t\t\t}\n\t\t\tif task.Done != nil {\n\t\t\t\ttask.Done <- err\n\t\t\t}\n\t\t}\n\t}\n}\n\n// TODO addr to node\nfunc reconnection(client **rpc.Client, addr string) {\n\tpfc.Meter(\"migrate.reconnection.\"+addr, 1)\n\n\tvar err error\n\n\tatomic.AddUint64(&stat_cnt[CONN_S_ERR], 1)\n\tif *client != nil {\n\t\t(*client).Close()\n\t}\n\n\t*client, err = dial(addr, time.Second)\n\tatomic.AddUint64(&stat_cnt[CONN_S_DIAL], 1)\n\n\tfor err != nil {\n\t\t//danger!! block routine\n\t\ttime.Sleep(time.Millisecond * 500)\n\t\t*client, err = dial(addr, time.Second)\n\t\tatomic.AddUint64(&stat_cnt[CONN_S_DIAL], 1)\n\t}\n}\n\nfunc query_data(client **rpc.Client, addr string,\n\targs interface{}, resp interface{}) error {\n\tvar (\n\t\terr error\n\t\ti   int\n\t)\n\n\tfor i = 0; i < 3; i++ {\n\t\terr = rpc_call(*client, \"Graph.Query\", args, resp,\n\t\t\ttime.Duration(g.Config().CallTimeout)*time.Millisecond)\n\n\t\tif err == nil {\n\t\t\tbreak\n\t\t}\n\t\tif err == rpc.ErrShutdown {\n\t\t\treconnection(client, addr)\n\t\t}\n\t}\n\treturn err\n}\n\nfunc send_data(client **rpc.Client, key string, addr string) error {\n\tvar (\n\t\terr  error\n\t\tflag uint32\n\t\tresp *cmodel.SimpleRpcResponse\n\t\ti    int\n\t)\n\n\t//remote\n\tif flag, err = store.GraphItems.GetFlag(key); err != nil {\n\t\treturn err\n\t}\n\tcfg := g.Config()\n\n\tstore.GraphItems.SetFlag(key, flag|g.GRAPH_F_SENDING)\n\n\titems := store.GraphItems.PopAll(key)\n\titems_size := len(items)\n\tif items_size == 0 {\n\t\tgoto out\n\t}\n\tresp = &cmodel.SimpleRpcResponse{}\n\n\tfor i = 0; i < 3; i++ {\n\t\terr = rpc_call(*client, \"Graph.Send\", items, resp,\n\t\t\ttime.Duration(cfg.CallTimeout)*time.Millisecond)\n\n\t\tif err == nil {\n\t\t\tgoto out\n\t\t}\n\t\tif err == rpc.ErrShutdown {\n\t\t\treconnection(client, addr)\n\t\t}\n\t}\n\t// err\n\tstore.GraphItems.PushAll(key, items)\n\t//flag |= g.GRAPH_F_ERR\nout:\n\tflag &= ^g.GRAPH_F_SENDING\n\tstore.GraphItems.SetFlag(key, flag)\n\treturn err\n\n}\n\nfunc fetch_rrd(client **rpc.Client, key string, addr string) error {\n\tvar (\n\t\terr      error\n\t\tflag     uint32\n\t\tmd5      string\n\t\tdsType   string\n\t\tfilename string\n\t\tstep, i  int\n\t\trrdfile  g.File\n\t)\n\n\tcfg := g.Config()\n\n\tif flag, err = store.GraphItems.GetFlag(key); err != nil {\n\t\treturn err\n\t}\n\n\tstore.GraphItems.SetFlag(key, flag|g.GRAPH_F_FETCHING)\n\n\tmd5, dsType, step, _ = g.SplitRrdCacheKey(key)\n\tfilename = g.RrdFileName(cfg.RRD.Storage, md5, dsType, step)\n\n\tfor i = 0; i < 3; i++ {\n\t\terr = rpc_call(*client, \"Graph.GetRrd\", key, &rrdfile,\n\t\t\ttime.Duration(cfg.CallTimeout)*time.Millisecond)\n\n\t\tif err == nil {\n\t\t\tdone := make(chan error, 1)\n\t\t\tio_task_chans[getIndex(md5)] <- &io_task_t{\n\t\t\t\tmethod: IO_TASK_M_WRITE,\n\t\t\t\targs: &g.File{\n\t\t\t\t\tFilename: filename,\n\t\t\t\t\tBody:     rrdfile.Body[:],\n\t\t\t\t},\n\t\t\t\tdone: done,\n\t\t\t}\n\t\t\tif err = <-done; err != nil {\n\t\t\t\tgoto out\n\t\t\t} else {\n\t\t\t\tflag &= ^g.GRAPH_F_MISS\n\t\t\t\tgoto out\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Println(err)\n\t\t}\n\t\tif err == rpc.ErrShutdown {\n\t\t\treconnection(client, addr)\n\t\t}\n\t}\nout:\n\tflag &= ^g.GRAPH_F_FETCHING\n\tstore.GraphItems.SetFlag(key, flag)\n\treturn err\n}\n\nfunc rpc_call(client *rpc.Client, method string, args interface{},\n\treply interface{}, timeout time.Duration) error {\n\tdone := make(chan *rpc.Call, 1)\n\tclient.Go(method, args, reply, done)\n\tselect {\n\tcase <-time.After(timeout):\n\t\treturn errors.New(\"i/o timeout[rpc]\")\n\tcase call := <-done:\n\t\tif call.Error == nil {\n\t\t\treturn nil\n\t\t} else {\n\t\t\treturn call.Error\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/graph/rrdtool/rrdtool.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rrdtool\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"math\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/rrdlite\"\n\t\"github.com/toolkits/file\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/store\"\n)\n\nvar (\n\tdisk_counter uint64\n\tnet_counter  uint64\n)\n\ntype fetch_t struct {\n\tfilename string\n\tcf       string\n\tstart    int64\n\tend      int64\n\tstep     int\n\tdata     []*cmodel.RRDData\n}\n\ntype flushfile_t struct {\n\tfilename string\n\titems    []*cmodel.GraphItem\n}\n\ntype readfile_t struct {\n\tfilename string\n\tdata     []byte\n}\n\nfunc Start() {\n\tcfg := g.Config()\n\tvar err error\n\t// check data dir\n\tif err = file.EnsureDirRW(cfg.RRD.Storage); err != nil {\n\t\tlog.Fatalln(\"rrdtool.Start error, bad data dir \"+cfg.RRD.Storage+\",\", err)\n\t}\n\n\tmigrate_start(cfg)\n\n\t// sync disk\n\tgo syncDisk()\n\tgo ioWorker()\n\tlog.Println(\"rrdtool.Start ok\")\n}\n\n// RRA.Point.Size\nconst (\n\tRRA1PointCnt   = 720 // 1m一个点存12h\n\tRRA5PointCnt   = 576 // 5m一个点存2d\n\tRRA20PointCnt  = 504 // 20m一个点存7d\n\tRRA180PointCnt = 766 // 3h一个点存3month\n\tRRA720PointCnt = 730 // 12h一个点存1year\n)\n\nfunc create(filename string, item *cmodel.GraphItem) error {\n\tnow := time.Now()\n\tstart := now.Add(time.Duration(-24) * time.Hour)\n\tstep := uint(item.Step)\n\n\tc := rrdlite.NewCreator(filename, start, step)\n\tc.DS(\"metric\", item.DsType, item.Heartbeat, item.Min, item.Max)\n\n\t// 设置各种归档策略\n\t// 1分钟一个点存 12小时\n\tc.RRA(\"AVERAGE\", 0, 1, RRA1PointCnt)\n\n\t// 5m一个点存2d\n\tc.RRA(\"AVERAGE\", 0, 5, RRA5PointCnt)\n\tc.RRA(\"MAX\", 0, 5, RRA5PointCnt)\n\tc.RRA(\"MIN\", 0, 5, RRA5PointCnt)\n\n\t// 20m一个点存7d\n\tc.RRA(\"AVERAGE\", 0, 20, RRA20PointCnt)\n\tc.RRA(\"MAX\", 0, 20, RRA20PointCnt)\n\tc.RRA(\"MIN\", 0, 20, RRA20PointCnt)\n\n\t// 3小时一个点存3个月\n\tc.RRA(\"AVERAGE\", 0, 180, RRA180PointCnt)\n\tc.RRA(\"MAX\", 0, 180, RRA180PointCnt)\n\tc.RRA(\"MIN\", 0, 180, RRA180PointCnt)\n\n\t// 12小时一个点存1year\n\tc.RRA(\"AVERAGE\", 0, 720, RRA720PointCnt)\n\tc.RRA(\"MAX\", 0, 720, RRA720PointCnt)\n\tc.RRA(\"MIN\", 0, 720, RRA720PointCnt)\n\n\treturn c.Create(true)\n}\n\nfunc update(filename string, items []*cmodel.GraphItem) error {\n\tu := rrdlite.NewUpdater(filename)\n\n\tfor _, item := range items {\n\t\tv := math.Abs(item.Value)\n\t\tif v > 1e+300 || (v < 1e-300 && v > 0) {\n\t\t\tcontinue\n\t\t}\n\t\tif item.DsType == \"DERIVE\" || item.DsType == \"COUNTER\" {\n\t\t\tu.Cache(item.Timestamp, int(item.Value))\n\t\t} else {\n\t\t\tu.Cache(item.Timestamp, item.Value)\n\t\t}\n\t}\n\n\treturn u.Update()\n}\n\n// flush to disk from memory\n// 最新的数据在列表的最后面\n// TODO fix me, filename fmt from item[0], it's hard to keep consistent\nfunc flushrrd(filename string, items []*cmodel.GraphItem) error {\n\tif items == nil || len(items) == 0 {\n\t\treturn errors.New(\"empty items\")\n\t}\n\n\tif !g.IsRrdFileExist(filename) {\n\t\tbaseDir := file.Dir(filename)\n\n\t\terr := file.InsureDir(baseDir)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = create(filename, items[0])\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn update(filename, items)\n}\n\nfunc ReadFile(filename, md5 string) ([]byte, error) {\n\tdone := make(chan error, 1)\n\ttask := &io_task_t{\n\t\tmethod: IO_TASK_M_READ,\n\t\targs:   &readfile_t{filename: filename},\n\t\tdone:   done,\n\t}\n\n\tio_task_chans[getIndex(md5)] <- task\n\terr := <-done\n\treturn task.args.(*readfile_t).data, err\n}\n\nfunc FlushFile(filename, md5 string, items []*cmodel.GraphItem) error {\n\tdone := make(chan error, 1)\n\tio_task_chans[getIndex(md5)] <- &io_task_t{\n\t\tmethod: IO_TASK_M_FLUSH,\n\t\targs: &flushfile_t{\n\t\t\tfilename: filename,\n\t\t\titems:    items,\n\t\t},\n\t\tdone: done,\n\t}\n\tatomic.AddUint64(&disk_counter, 1)\n\treturn <-done\n}\n\nfunc Fetch(filename string, md5 string, cf string, start, end int64, step int) ([]*cmodel.RRDData, error) {\n\tdone := make(chan error, 1)\n\ttask := &io_task_t{\n\t\tmethod: IO_TASK_M_FETCH,\n\t\targs: &fetch_t{\n\t\t\tfilename: filename,\n\t\t\tcf:       cf,\n\t\t\tstart:    start,\n\t\t\tend:      end,\n\t\t\tstep:     step,\n\t\t},\n\t\tdone: done,\n\t}\n\tio_task_chans[getIndex(md5)] <- task\n\terr := <-done\n\treturn task.args.(*fetch_t).data, err\n}\n\nfunc fetch(filename string, cf string, start, end int64, step int) ([]*cmodel.RRDData, error) {\n\tstart_t := time.Unix(start, 0)\n\tend_t := time.Unix(end, 0)\n\tstep_t := time.Duration(step) * time.Second\n\n\tfetchRes, err := rrdlite.Fetch(filename, cf, start_t, end_t, step_t)\n\tif err != nil {\n\t\treturn []*cmodel.RRDData{}, err\n\t}\n\n\tdefer fetchRes.FreeValues()\n\n\tvalues := fetchRes.Values()\n\tsize := len(values)\n\tret := make([]*cmodel.RRDData, size)\n\n\tstart_ts := fetchRes.Start.Unix()\n\tstep_s := fetchRes.Step.Seconds()\n\n\tfor i, val := range values {\n\t\tts := start_ts + int64(i+1)*int64(step_s)\n\t\td := &cmodel.RRDData{\n\t\t\tTimestamp: ts,\n\t\t\tValue:     cmodel.JsonFloat(val),\n\t\t}\n\t\tret[i] = d\n\t}\n\n\treturn ret, nil\n}\n\nfunc FlushAll(force bool) {\n\tn := store.GraphItems.Size / 10\n\tfor i := 0; i < store.GraphItems.Size; i++ {\n\t\tFlushRRD(i, force)\n\t\tif i%n == 0 {\n\t\t\tlog.Printf(\"flush hash idx:%03d size:%03d disk:%08d net:%08d\\n\",\n\t\t\t\ti, store.GraphItems.Size, disk_counter, net_counter)\n\t\t}\n\t}\n\tlog.Printf(\"flush hash done (disk:%08d net:%08d)\\n\", disk_counter, net_counter)\n}\n\nfunc CommitByKey(key string) {\n\tmd5, dsType, step, err := g.SplitRrdCacheKey(key)\n\tif err != nil {\n\t\treturn\n\t}\n\tfilename := g.RrdFileName(g.Config().RRD.Storage, md5, dsType, step)\n\n\titems := store.GraphItems.PopAll(key)\n\tif len(items) == 0 {\n\t\treturn\n\t}\n\tFlushFile(filename, md5, items)\n}\n\nfunc PullByKey(key string) {\n\tdone := make(chan error)\n\n\titem := store.GraphItems.First(key)\n\tif item == nil {\n\t\treturn\n\t}\n\tnode, err := Consistent.Get(item.PrimaryKey())\n\tif err != nil {\n\t\treturn\n\t}\n\tNet_task_ch[node] <- &Net_task_t{\n\t\tMethod: NET_TASK_M_PULL,\n\t\tKey:    key,\n\t\tDone:   done,\n\t}\n\t// net_task slow, shouldn't block syncDisk() or FlushAll()\n\t// warning: recev sigout when migrating, maybe lost memory data\n\tgo func() {\n\t\terr := <-done\n\t\tif err != nil {\n\t\t\tlog.Printf(\"get %s from remote err[%s]\\n\", key, err)\n\t\t\treturn\n\t\t}\n\t\tatomic.AddUint64(&net_counter, 1)\n\t\t//todo: flushfile after getfile? not yet\n\t}()\n}\n\nfunc FlushRRD(idx int, force bool) {\n\tbegin := time.Now()\n\tatomic.StoreInt32(&flushrrd_timeout, 0)\n\n\tkeys := store.GraphItems.KeysByIndex(idx)\n\tif len(keys) == 0 {\n\t\treturn\n\t}\n\n\tfor _, key := range keys {\n\t\tflag, _ := store.GraphItems.GetFlag(key)\n\n\t\t//write err data to local filename\n\t\tif force == false && g.Config().Migrate.Enabled && flag&g.GRAPH_F_MISS != 0 {\n\t\t\tif time.Since(begin) > time.Millisecond*g.FLUSH_DISK_STEP {\n\t\t\t\tatomic.StoreInt32(&flushrrd_timeout, 1)\n\t\t\t}\n\t\t\tPullByKey(key)\n\t\t} else if force || shouldFlush(key) {\n\t\t\tCommitByKey(key)\n\t\t}\n\t}\n}\n\nfunc shouldFlush(key string) bool {\n\n\tif store.GraphItems.ItemCnt(key) >= g.FLUSH_MIN_COUNT {\n\t\treturn true\n\t}\n\n\tdeadline := time.Now().Unix() - int64(g.FLUSH_MAX_WAIT)\n\tback := store.GraphItems.Back(key)\n\tif back != nil && back.Timestamp <= deadline {\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "modules/graph/rrdtool/sync_disk.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rrdtool\n\nimport (\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/graph/store\"\n\t\"github.com/toolkits/file\"\n)\n\nconst (\n\t_ = iota\n\tIO_TASK_M_READ\n\tIO_TASK_M_WRITE\n\tIO_TASK_M_FLUSH\n\tIO_TASK_M_FETCH\n)\n\ntype io_task_t struct {\n\tmethod int\n\targs   interface{}\n\tdone   chan error\n}\n\nvar (\n\tOut_done_chan chan int\n\tio_task_chans []chan *io_task_t\n)\n\nfunc InitChannel() {\n\tOut_done_chan = make(chan int, 1)\n\tioWorkerNum := g.Config().IOWorkerNum\n\tio_task_chans = make([]chan *io_task_t, ioWorkerNum)\n\tfor i := 0; i < ioWorkerNum; i++ {\n\t\tio_task_chans[i] = make(chan *io_task_t, 16)\n\t}\n}\n\nfunc syncDisk() {\n\ttime.Sleep(time.Second * g.CACHE_DELAY)\n\tticker := time.NewTicker(time.Millisecond * g.FLUSH_DISK_STEP)\n\tdefer ticker.Stop()\n\tvar idx int = 0\n\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\tidx = idx % store.GraphItems.Size\n\t\t\tFlushRRD(idx, false)\n\t\t\tidx += 1\n\t\tcase <-Out_done_chan:\n\t\t\tlog.Println(\"cron recv sigout and exit...\")\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// WriteFile writes data to a file named by filename.\n// file must not exist\nfunc writeFile(filename string, data []byte, perm os.FileMode) error {\n\tf, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)\n\tif err != nil {\n\t\treturn err\n\t}\n\tn, err := f.Write(data)\n\tif err == nil && n < len(data) {\n\t\terr = io.ErrShortWrite\n\t}\n\tif err1 := f.Close(); err == nil {\n\t\terr = err1\n\t}\n\treturn err\n}\n\nfunc ioWorker() {\n\tioWorkerNum := g.Config().IOWorkerNum\n\tfor i := 0; i < ioWorkerNum; i++ {\n\t\tgo func(i int) {\n\t\t\tvar err error\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase task := <-io_task_chans[i]:\n\t\t\t\t\tif task.method == IO_TASK_M_READ {\n\t\t\t\t\t\tif args, ok := task.args.(*readfile_t); ok {\n\t\t\t\t\t\t\targs.data, err = ioutil.ReadFile(args.filename)\n\t\t\t\t\t\t\ttask.done <- err\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if task.method == IO_TASK_M_WRITE {\n\t\t\t\t\t\t//filename must not exist\n\t\t\t\t\t\tif args, ok := task.args.(*g.File); ok {\n\t\t\t\t\t\t\tbaseDir := file.Dir(args.Filename)\n\t\t\t\t\t\t\tif err = file.InsureDir(baseDir); err != nil {\n\t\t\t\t\t\t\t\ttask.done <- err\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttask.done <- writeFile(args.Filename, args.Body, 0644)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if task.method == IO_TASK_M_FLUSH {\n\t\t\t\t\t\tif args, ok := task.args.(*flushfile_t); ok {\n\t\t\t\t\t\t\ttask.done <- flushrrd(args.filename, args.items)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if task.method == IO_TASK_M_FETCH {\n\t\t\t\t\t\tif args, ok := task.args.(*fetch_t); ok {\n\t\t\t\t\t\t\targs.data, err = fetch(args.filename, args.cf, args.start, args.end, args.step)\n\t\t\t\t\t\t\ttask.done <- err\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}(i)\n\t}\n}\n"
  },
  {
    "path": "modules/graph/rrdtool/utils.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rrdtool\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n)\n\n// getIndex\n// 输入: md5\n// 输出: slice的index\nfunc getIndex(md5 string) (index int) {\n\tbatchNum := g.Config().IOWorkerNum\n\tfirstBytesSize := g.Config().FirstBytesSize\n\n\tif batchNum <= 1 || len(md5) < firstBytesSize || firstBytesSize == 0 {\n\t\treturn 0\n\t}\n\n\tm, err := strconv.ParseInt(md5[0:firstBytesSize], 16, 64)\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\treturn int(m) % int(batchNum)\n}\n"
  },
  {
    "path": "modules/graph/store/history.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage store\n\nimport (\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\ttlist \"github.com/toolkits/container/list\"\n\ttmap \"github.com/toolkits/container/nmap\"\n)\n\nconst (\n\tdefaultHistorySize = 3\n)\n\nvar (\n\t// mem:  front = = = back\n\t// time: latest ...  old\n\tHistoryCache = tmap.NewSafeMap()\n)\n\nfunc GetLastItem(key string) *cmodel.GraphItem {\n\titemlist, found := HistoryCache.Get(key)\n\tif !found || itemlist == nil {\n\t\treturn &cmodel.GraphItem{}\n\t}\n\n\tfirst := itemlist.(*tlist.SafeListLimited).Front()\n\tif first == nil {\n\t\treturn &cmodel.GraphItem{}\n\t}\n\n\treturn first.(*cmodel.GraphItem)\n}\n\nfunc GetAllItems(key string) []*cmodel.GraphItem {\n\tret := make([]*cmodel.GraphItem, 0)\n\titemlist, found := HistoryCache.Get(key)\n\tif !found || itemlist == nil {\n\t\treturn ret\n\t}\n\n\tall := itemlist.(*tlist.SafeListLimited).FrontAll()\n\tfor _, item := range all {\n\t\tif item == nil {\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, item.(*cmodel.GraphItem))\n\t}\n\treturn ret\n}\n\nfunc AddItem(key string, val *cmodel.GraphItem) {\n\titemlist, found := HistoryCache.Get(key)\n\tvar slist *tlist.SafeListLimited\n\tif !found {\n\t\tslist = tlist.NewSafeListLimited(defaultHistorySize)\n\t\tHistoryCache.Put(key, slist)\n\t} else {\n\t\tslist = itemlist.(*tlist.SafeListLimited)\n\t}\n\n\t// old item should be drop\n\tfirst := slist.Front()\n\tif first == nil || first.(*cmodel.GraphItem).Timestamp < val.Timestamp { // first item or latest one\n\t\tslist.PushFrontViolently(val)\n\t}\n}\n"
  },
  {
    "path": "modules/graph/store/linkedlist.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage store\n\nimport (\n\t\"container/list\"\n\t\"sync\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n)\n\ntype SafeLinkedList struct {\n\tsync.RWMutex\n\tFlag uint32\n\tL    *list.List\n}\n\n// 新创建SafeLinkedList容器\nfunc NewSafeLinkedList() *SafeLinkedList {\n\treturn &SafeLinkedList{L: list.New()}\n}\n\nfunc (this *SafeLinkedList) PushFront(v interface{}) *list.Element {\n\tthis.Lock()\n\tdefer this.Unlock()\n\treturn this.L.PushFront(v)\n}\n\nfunc (this *SafeLinkedList) Front() *list.Element {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.L.Front()\n}\n\nfunc (this *SafeLinkedList) PopBack() *list.Element {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tback := this.L.Back()\n\tif back != nil {\n\t\tthis.L.Remove(back)\n\t}\n\n\treturn back\n}\n\nfunc (this *SafeLinkedList) Back() *list.Element {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\treturn this.L.Back()\n}\n\nfunc (this *SafeLinkedList) Len() int {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.L.Len()\n}\n\n// remain参数表示要给linkedlist中留几个元素\n// 在cron中刷磁盘的时候要留一个，用于创建数据库索引\n// 在程序退出的时候要一个不留的全部刷到磁盘\nfunc (this *SafeLinkedList) PopAll() []*cmodel.GraphItem {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tsize := this.L.Len()\n\tif size <= 0 {\n\t\treturn []*cmodel.GraphItem{}\n\t}\n\n\tret := make([]*cmodel.GraphItem, 0, size)\n\n\tfor i := 0; i < size; i++ {\n\t\titem := this.L.Back()\n\t\tret = append(ret, item.Value.(*cmodel.GraphItem))\n\t\tthis.L.Remove(item)\n\t}\n\n\treturn ret\n}\n\n//restore PushAll\nfunc (this *SafeLinkedList) PushAll(items []*cmodel.GraphItem) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tsize := len(items)\n\tif size > 0 {\n\t\tfor i := size - 1; i >= 0; i-- {\n\t\t\tthis.L.PushBack(items[i])\n\t\t}\n\t}\n}\n\n//return为倒叙的?\nfunc (this *SafeLinkedList) FetchAll() ([]*cmodel.GraphItem, uint32) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tcount := this.L.Len()\n\tret := make([]*cmodel.GraphItem, 0, count)\n\n\tp := this.L.Back()\n\tfor p != nil {\n\t\tret = append(ret, p.Value.(*cmodel.GraphItem))\n\t\tp = p.Prev()\n\t}\n\n\treturn ret, this.Flag\n}\n"
  },
  {
    "path": "modules/graph/store/store.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage store\n\nimport (\n\t\"container/list\"\n\t\"errors\"\n\t\"hash/crc32\"\n\t\"log\"\n\t\"sync\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/graph/g\"\n)\n\nvar GraphItems *GraphItemMap\n\ntype GraphItemMap struct {\n\tsync.RWMutex\n\tA    []map[string]*SafeLinkedList\n\tSize int\n}\n\nfunc (this *GraphItemMap) Get(key string) (*SafeLinkedList, bool) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tval, ok := this.A[idx][key]\n\treturn val, ok\n}\n\n// Remove method remove key from GraphItemMap, return true if exists\nfunc (this *GraphItemMap) Remove(key string) bool {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\t_, exists := this.A[idx][key]\n\tif !exists {\n\t\treturn false\n\t}\n\n\tdelete(this.A[idx], key)\n\treturn true\n}\n\nfunc (this *GraphItemMap) Getitems(idx int) map[string]*SafeLinkedList {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\titems := this.A[idx]\n\tthis.A[idx] = make(map[string]*SafeLinkedList)\n\treturn items\n}\n\nfunc (this *GraphItemMap) Set(key string, val *SafeLinkedList) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tthis.A[idx][key] = val\n}\n\nfunc (this *GraphItemMap) Len() int {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tvar l int\n\tfor i := 0; i < this.Size; i++ {\n\t\tl += len(this.A[i])\n\t}\n\treturn l\n}\n\nfunc (this *GraphItemMap) First(key string) *cmodel.GraphItem {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tsl, ok := this.A[idx][key]\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tfirst := sl.Front()\n\tif first == nil {\n\t\treturn nil\n\t}\n\n\treturn first.Value.(*cmodel.GraphItem)\n}\n\nfunc (this *GraphItemMap) PushAll(key string, items []*cmodel.GraphItem) error {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tsl, ok := this.A[idx][key]\n\tif !ok {\n\t\treturn errors.New(\"not exist\")\n\t}\n\tsl.PushAll(items)\n\treturn nil\n}\n\nfunc (this *GraphItemMap) GetFlag(key string) (uint32, error) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tsl, ok := this.A[idx][key]\n\tif !ok {\n\t\treturn 0, errors.New(\"not exist\")\n\t}\n\treturn sl.Flag, nil\n}\n\nfunc (this *GraphItemMap) SetFlag(key string, flag uint32) error {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tsl, ok := this.A[idx][key]\n\tif !ok {\n\t\treturn errors.New(\"not exist\")\n\t}\n\tsl.Flag = flag\n\treturn nil\n}\n\nfunc (this *GraphItemMap) PopAll(key string) []*cmodel.GraphItem {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tsl, ok := this.A[idx][key]\n\tif !ok {\n\t\treturn []*cmodel.GraphItem{}\n\t}\n\treturn sl.PopAll()\n}\n\nfunc (this *GraphItemMap) FetchAll(key string) ([]*cmodel.GraphItem, uint32) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tsl, ok := this.A[idx][key]\n\tif !ok {\n\t\treturn []*cmodel.GraphItem{}, 0\n\t}\n\n\treturn sl.FetchAll()\n}\n\nfunc hashKey(key string) uint32 {\n\tif len(key) < 64 {\n\t\tvar scratch [64]byte\n\t\tcopy(scratch[:], key)\n\t\treturn crc32.ChecksumIEEE(scratch[:len(key)])\n\t}\n\treturn crc32.ChecksumIEEE([]byte(key))\n}\n\nfunc getWts(key string, now int64) int64 {\n\tinterval := int64(g.CACHE_TIME)\n\treturn now + interval - (int64(hashKey(key)) % interval)\n}\n\nfunc (this *GraphItemMap) PushFront(key string,\n\titem *cmodel.GraphItem, md5 string, cfg *g.GlobalConfig) {\n\tif linkedList, exists := this.Get(key); exists {\n\t\tlinkedList.PushFront(item)\n\t} else {\n\t\t//log.Println(\"new key:\", key)\n\t\tsafeList := &SafeLinkedList{L: list.New()}\n\t\tsafeList.L.PushFront(item)\n\n\t\tif cfg.Migrate.Enabled && !g.IsRrdFileExist(g.RrdFileName(\n\t\t\tcfg.RRD.Storage, md5, item.DsType, item.Step)) {\n\t\t\tsafeList.Flag = g.GRAPH_F_MISS\n\t\t}\n\t\tthis.Set(key, safeList)\n\t}\n}\n\nfunc (this *GraphItemMap) KeysByIndex(idx int) []string {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\n\tcount := len(this.A[idx])\n\tif count == 0 {\n\t\treturn []string{}\n\t}\n\n\tkeys := make([]string, 0, count)\n\tfor key := range this.A[idx] {\n\t\tkeys = append(keys, key)\n\t}\n\n\treturn keys\n}\n\nfunc (this *GraphItemMap) Back(key string) *cmodel.GraphItem {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tL, ok := this.A[idx][key]\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tback := L.Back()\n\tif back == nil {\n\t\treturn nil\n\t}\n\n\treturn back.Value.(*cmodel.GraphItem)\n}\n\n// 指定key对应的Item数量\nfunc (this *GraphItemMap) ItemCnt(key string) int {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tidx := hashKey(key) % uint32(this.Size)\n\tL, ok := this.A[idx][key]\n\tif !ok {\n\t\treturn 0\n\t}\n\treturn L.Len()\n}\n\nfunc init() {\n\tsize := g.CACHE_TIME / g.FLUSH_DISK_STEP\n\tif size < 0 {\n\t\tlog.Panicf(\"store.init, bad size %d\\n\", size)\n\t}\n\n\tGraphItems = &GraphItemMap{\n\t\tA:    make([]map[string]*SafeLinkedList, size),\n\t\tSize: size,\n\t}\n\tfor i := 0; i < size; i++ {\n\t\tGraphItems.A[i] = make(map[string]*SafeLinkedList)\n\t}\n}\n"
  },
  {
    "path": "modules/graph/test/debug",
    "content": "#!/bin/bash\n## test home\ntestdir=$(cd $(dirname $0)/; pwd)\n## word home\nworkdir=$(dirname $testdir)\ncd $workdir\n\nmodule=graph\napp=falcon-$module\npidfile=var/app.pid\nlogfile=var/app.log\ncontrol=./control\nhttpprex=\"127.0.0.1:6071\"\nrpcprex=\"127.0.0.1:6070\"\n\n## statistics\nfunction counter(){\n    curl -s \"$httpprex/counter/all\" | python -m json.tool\n}\n\n## config\nfunction config(){\n    action=$1\n    case $action in\n        \"reload\")\n            curl -s \"$httpprex/config/reload\" | python -m json.tool\n            ;;\n        *)\n            curl -s \"$httpprex/config\" | python -m json.tool\n            ;;\n    esac\n}\n\n\nfunction index(){\n    e=\"test.graph.endpoint.niean.1\"\n    m=\"test.graph.metric.1\"\n    t=\"tag0=tag0-dummy-1,tag1=tag1-dummy-1,tag2=tag2-dummy-1\"\n    dt=\"GAUGE\"\n    step=\"60\"\n    curl -s \"$httpprex/index/cache/$e/$m/$step/$dt/$t\" | python -m json.tool\n}\n\nfunction index_v2(){\n    e=\"test.graph.endpoint.niean/1\"\n    m=\"test.graph.metric/1\"\n    t=\"tag/0=tag0-dummy-1,tag1=tag1-dummy-1,tag2=tag2-dummy-1\"\n    dt=\"GAUGE\"\n    step=\"60\"\n    curl -s \"$httpprex/v2/index/cache?e=$e&m=$m&t=$t&type=$dt&step=$step\" | python -m json.tool\n}\n\nfunction index_update_all(){\n    curl -s \"$httpprex/index/updateAll\" | python -m json.tool\n}\n\nfunction index_update_one(){\n    e=\"test.graph.endpoint.niean.1\"\n    m=\"test.graph.metric.1\"\n    tags=\"tag0=tag0-dummy-1,tag1=tag1-dummy-1,tag2=tag2-dummy-1\"\n    dt=\"GAUGE\"\n    step=\"60\"\n    curl -s \"$httpprex/index/updateOne?EndPoint=$e&Metric=$m&Tags=$tags&DsType=$dt&Step=$step\" | python -m json.tool\n}\n\n## history\nfunction fetch_history(){\n    e=\"test.graph.endpoint.niean.1\"\n    m=\"test.graph.metric.1\"\n    tags=\"tag0=tag0-dummy-1,tag1=tag1-dummy-1,tag2=tag2-dummy-1\"\n    curl -s \"$httpprex/history/$e/$m/$tags\" | python -m json.tool\n}\nfunction fetch_history_v2(){\n    e=\"test.graph.endpoint.niean/1\"\n    m=\"test.graph.metric/1\"\n    tags=\"tag/0=tag0-dummy-1,tag1=tag1-dummy-1,tag2=tag2-dummy-1\"\n    curl -s \"$httpprex/v2/history?e=$e&m=$m&t=$tags\" | python -m json.tool\n}\n\n## last\nfunction fetch_last(){\n    e=\"test.graph.endpoint.niean.1\"\n    m=\"test.graph.metric.1\"\n    tags=\"tag0=tag0-dummy-1,tag1=tag1-dummy-1,tag2=tag2-dummy-1\"\n    curl -s \"$httpprex/last/$e/$m/$tags\" | python -m json.tool\n}\n\n## send\nfunction api_send(){\n    e=\"test.graph.endpoint.niean.1\"\n    m=\"test.graph.metric.1\"\n    ts=`date +%s`\n    dsType=\"GAUGE\"\n    step=60\n    value=`expr $ts % 60`\n    tags=\"tag0=tag0-dummy-1,tag1=tag1-dummy-1,tag2=tag2-dummy-1\"\n    curl -s \"$httpprex/api/recv/$e/$m/$ts/$step/$dsType/$value/$tags\" | python -m json.tool\n}\n\nfunction api_send_v2(){\n    e=\"test.graph.endpoint.niean/1\"\n    m=\"test.graph.metric/1\"\n    ts=`date +%s`\n    dsType=\"GAUGE\"\n    step=60\n    value=`expr $ts % 60`\n    tags=\"tag/0=tag0-dummy-1,tag1=tag1-dummy-1,tag2=tag2-dummy-1\"\n    curl -s \"$httpprex/v2/api/recv?e=$e&m=$m&ts=$ts&step=$step&type=$dsType&v=$value&t=$tags\" | python -m json.tool\n}\n\n\n## tail\nfunction tail_log(){\n    $control tail\n}\n\n## build\nfunction build(){\n    $control build\n    [ $? -eq 0 ] && echo -e \"build ok\" || { echo -e \"build error\"; exit 1; }\n}\nfunction start(){\n    $control start\n}\nfunction stop(){\n    $control stop\n}\n\n\naction=$1\ncase $action in\n    \"build\")\n        build\n        ;;\n    \"start\")\n        start\n        ;;\n    \"stop\")\n        stop\n        ;;\n    \"restart\")\n        stop && build && start\n        ;;\n    \"config\")\n        config $2\n        ;;\n    \"index\")\n        index\n        ;;\n    \"index2\")\n        index_v2\n        ;;\n    \"index_update_all\")\n        index_update_all\n        ;;\n    \"index_update_one\")\n        index_update_one\n        ;;\n    \"filter\")\n        filter_recv\n        ;;\n    \"history\")\n        fetch_history\n        ;;\n    \"history2\")\n        fetch_history_v2\n        ;;\n    \"last\")\n        fetch_last\n        ;;\n    \"send\")\n        api_send\n        ;;\n    \"send2\")\n        api_send_v2\n        ;;\n    \"tail\")\n        tail_log\n        ;;\n    *)\n        counter\n        ;;\nesac\n\n"
  },
  {
    "path": "modules/graph/test/graph.list",
    "content": "test.hostname01:6071\ntest.hostname02:6071\ntest.hostname03:6071\n"
  },
  {
    "path": "modules/graph/test/http.recv.history",
    "content": "#!/bin/bash\ne=$1\nm=$2\ntags=$3\n\nhost_file=./graph.list\nfor i in `cat $host_file`;\ndo\n    printf \"%s\\n\" $i\n    curl -s \"$i/history/$e/$m/$tags\"\n    printf \"\\n\"\n    sleep 0.1\ndone\n"
  },
  {
    "path": "modules/graph/version.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// build !release\npackage main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  },
  {
    "path": "modules/hbs/.gitignore",
    "content": "*.log\n*.o\n*.so\n*.swp\n*.swo\n/falcon-hbs*\n/hbs*\n/log\n/var\n/tmp\n/cfg.json\n/gitversion\n\n"
  },
  {
    "path": "modules/hbs/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "modules/hbs/NOTICE",
    "content": "Open-Falcon\n\nCopyright (c) 2014-2015 Xiaomi, Inc. All Rights Reserved.\n\nThis product is licensed to you under the Apache License, Version 2.0 (the \"License\").\nYou may not use this product except in compliance with the License.\n\nThis product may include a number of subcomponents with separate copyright notices\nand license terms. Your use of these subcomponents is subject to the terms and\nconditions of the subcomponent's license, as noted in the LICENSE file.\n"
  },
  {
    "path": "modules/hbs/README.md",
    "content": "falcon-hbs\n==========\n\nHeartbeat Server. 所有Agent都会连到hbs，每分钟发一次心跳，汇报自己的hostname、ip、agent version、plugin version，hbs据此\n填充host表。agent还会通过hbs拿到应该监控的端口、进程，应该执行的插件等信息。\n\nhbs要能够处理agent的上述请求，就需要与portal的数据库打交道，这是无论如何无法避免的，那就为hbs再赋予一个功能：DB的缓存器。judge\n也需要通过portal的DB拿到策略列表，在一个大点的公司，judge实例可能比较多，几十个、甚至上百个，有了hbs这个DB缓存器在这了，judge就\n无需直接访问DB了，从hbs获取策略列表即可。如此一来，hbs可以每分钟从DB读取一次数据，这一分钟内所有judge的请求都可以直接读取内存。\n另外，DB存的是关系型数据，需要做一些转换才能被judge使用，hbs从DB中读取到数据之后顺便把转换也做了，这样所有judge就无需再做转换了。\n\n所以hbs的逻辑就变成了：每分钟从DB中load各种数据，处理后放到内存里，静待agent、judge的请求。\n\n## Installation\n\n```bash\n# set $GOPATH and $GOROOT\nmkdir -p $GOPATH/src/github.com/open-falcon\ncd $GOPATH/src/github.com/open-falcon\ngit clone https://github.com/open-falcon/hbs.git\ncd hbs\ngo get ./...\n./control build\n./control start\n```\n\n## Configuration\n\n- database: portal的db连接地址\n- maxIdle: 数据库连接池的MaxIdle配置\n- listen: 监听的rpc端口，judge要通过这个端口拿到策略列表\n- trustable: 可信ip列表，安全起见留空即可\n- http: 监听的http地址，主要是做调试\n"
  },
  {
    "path": "modules/hbs/cache/agents.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cache\n\n// 每个agent心跳上来的时候立马更新一下数据库是没必要的\n// 缓存起来，每隔一个小时写一次DB\n// 提供http接口查询机器信息，排查重名机器的时候比较有用\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/db\"\n)\n\ntype SafeAgents struct {\n\tsync.RWMutex\n\tM map[string]*model.AgentUpdateInfo\n}\n\nvar Agents = NewSafeAgents()\n\nfunc NewSafeAgents() *SafeAgents {\n\treturn &SafeAgents{M: make(map[string]*model.AgentUpdateInfo)}\n}\n\nfunc (this *SafeAgents) Put(req *model.AgentReportRequest) {\n\tval := &model.AgentUpdateInfo{\n\t\tLastUpdate:    time.Now().Unix(),\n\t\tReportRequest: req,\n\t}\n\n\tif agentInfo, exists := this.Get(req.Hostname); !exists ||\n\t\tagentInfo.ReportRequest.AgentVersion != req.AgentVersion ||\n\t\tagentInfo.ReportRequest.IP != req.IP ||\n\t\tagentInfo.ReportRequest.PluginVersion != req.PluginVersion {\n\n\t\tdb.UpdateAgent(val)\n\t}\n\n\t// 更新hbs 时间\n\tthis.Lock()\n\tthis.M[req.Hostname] = val\n\tthis.Unlock()\n}\n\nfunc (this *SafeAgents) Get(hostname string) (*model.AgentUpdateInfo, bool) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tval, exists := this.M[hostname]\n\treturn val, exists\n}\n\nfunc (this *SafeAgents) Delete(hostname string) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tdelete(this.M, hostname)\n}\n\nfunc (this *SafeAgents) Keys() []string {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tcount := len(this.M)\n\tkeys := make([]string, count)\n\ti := 0\n\tfor hostname := range this.M {\n\t\tkeys[i] = hostname\n\t\ti++\n\t}\n\treturn keys\n}\n\nfunc DeleteStaleAgents() {\n\tduration := time.Hour * time.Duration(24)\n\tfor {\n\t\ttime.Sleep(duration)\n\t\tdeleteStaleAgents()\n\t}\n}\n\nfunc deleteStaleAgents() {\n\t// 一天都没有心跳的Agent，从内存中干掉\n\tbefore := time.Now().Unix() - 3600*24\n\tkeys := Agents.Keys()\n\tcount := len(keys)\n\tif count == 0 {\n\t\treturn\n\t}\n\n\tfor i := 0; i < count; i++ {\n\t\tcurr, _ := Agents.Get(keys[i])\n\t\tif curr.LastUpdate < before {\n\t\t\tAgents.Delete(curr.ReportRequest.Hostname)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/hbs/cache/cache.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cache\n\nimport (\n\t\"log\"\n\t\"time\"\n)\n\nfunc Init() {\n\tlog.Println(\"cache begin\")\n\n\tlog.Println(\"#1 GroupPlugins...\")\n\tGroupPlugins.Init()\n\n\tlog.Println(\"#2 GroupTemplates...\")\n\tGroupTemplates.Init()\n\n\tlog.Println(\"#3 HostGroupsMap...\")\n\tHostGroupsMap.Init()\n\n\tlog.Println(\"#4 HostMap...\")\n\tHostMap.Init()\n\n\tlog.Println(\"#5 TemplateCache...\")\n\tTemplateCache.Init()\n\n\tlog.Println(\"#6 Strategies...\")\n\tStrategies.Init(TemplateCache.GetMap())\n\n\tlog.Println(\"#7 HostTemplateIds...\")\n\tHostTemplateIds.Init()\n\n\tlog.Println(\"#8 ExpressionCache...\")\n\tExpressionCache.Init()\n\n\tlog.Println(\"#9 MonitoredHosts...\")\n\tMonitoredHosts.Init()\n\n\tlog.Println(\"cache done\")\n\n\tgo LoopInit()\n\n}\n\nfunc LoopInit() {\n\tfor {\n\t\ttime.Sleep(time.Minute)\n\t\tGroupPlugins.Init()\n\t\tGroupTemplates.Init()\n\t\tHostGroupsMap.Init()\n\t\tHostMap.Init()\n\t\tTemplateCache.Init()\n\t\tStrategies.Init(TemplateCache.GetMap())\n\t\tHostTemplateIds.Init()\n\t\tExpressionCache.Init()\n\t\tMonitoredHosts.Init()\n\t}\n}\n"
  },
  {
    "path": "modules/hbs/cache/expressions.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cache\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/db\"\n\t\"sync\"\n)\n\ntype SafeExpressionCache struct {\n\tsync.RWMutex\n\tL []*model.Expression\n}\n\nvar ExpressionCache = &SafeExpressionCache{}\n\nfunc (this *SafeExpressionCache) Get() []*model.Expression {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.L\n}\n\nfunc (this *SafeExpressionCache) Init() {\n\tes, err := db.QueryExpressions()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.L = es\n}\n"
  },
  {
    "path": "modules/hbs/cache/groups.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cache\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/db\"\n\t\"sync\"\n)\n\n// 一个机器可能在多个group下，做一个map缓存hostid与groupid的对应关系\ntype SafeHostGroupsMap struct {\n\tsync.RWMutex\n\tM map[int][]int\n}\n\nvar HostGroupsMap = &SafeHostGroupsMap{M: make(map[int][]int)}\n\nfunc (this *SafeHostGroupsMap) GetGroupIds(hid int) ([]int, bool) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tgids, exists := this.M[hid]\n\treturn gids, exists\n}\n\nfunc (this *SafeHostGroupsMap) Init() {\n\tm, err := db.QueryHostGroups()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n"
  },
  {
    "path": "modules/hbs/cache/hosts.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cache\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/db\"\n\t\"sync\"\n)\n\n// 每次心跳的时候agent把hostname汇报上来，经常要知道这个机器的hostid，把此信息缓存\n// key: hostname value: hostid\ntype SafeHostMap struct {\n\tsync.RWMutex\n\tM map[string]int\n}\n\nvar HostMap = &SafeHostMap{M: make(map[string]int)}\n\nfunc (this *SafeHostMap) GetID(hostname string) (int, bool) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tid, exists := this.M[hostname]\n\treturn id, exists\n}\n\nfunc (this *SafeHostMap) Init() {\n\tm, err := db.QueryHosts()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n\ntype SafeMonitoredHosts struct {\n\tsync.RWMutex\n\tM map[int]*model.Host\n}\n\nvar MonitoredHosts = &SafeMonitoredHosts{M: make(map[int]*model.Host)}\n\nfunc (this *SafeMonitoredHosts) Get() map[int]*model.Host {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.M\n}\n\nfunc (this *SafeMonitoredHosts) Init() {\n\tm, err := db.QueryMonitoredHosts()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n"
  },
  {
    "path": "modules/hbs/cache/plugins.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cache\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/db\"\n\t\"sort\"\n\t\"sync\"\n)\n\n// 一个HostGroup可以绑定多个Plugin\ntype SafeGroupPlugins struct {\n\tsync.RWMutex\n\tM map[int][]string\n}\n\nvar GroupPlugins = &SafeGroupPlugins{M: make(map[int][]string)}\n\nfunc (this *SafeGroupPlugins) GetPlugins(gid int) ([]string, bool) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tplugins, exists := this.M[gid]\n\treturn plugins, exists\n}\n\nfunc (this *SafeGroupPlugins) Init() {\n\tm, err := db.QueryPlugins()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n\n// 根据hostname获取关联的插件\nfunc GetPlugins(hostname string) []string {\n\thid, exists := HostMap.GetID(hostname)\n\tif !exists {\n\t\treturn []string{}\n\t}\n\n\tgids, exists := HostGroupsMap.GetGroupIds(hid)\n\tif !exists {\n\t\treturn []string{}\n\t}\n\n\t// 因为机器关联了多个Group，每个Group可能关联多个Plugin，故而一个机器关联的Plugin可能重复\n\tpluginDirs := make(map[string]struct{})\n\tfor _, gid := range gids {\n\t\tplugins, exists := GroupPlugins.GetPlugins(gid)\n\t\tif !exists {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, plugin := range plugins {\n\t\t\tpluginDirs[plugin] = struct{}{}\n\t\t}\n\t}\n\n\tsize := len(pluginDirs)\n\tif size == 0 {\n\t\treturn []string{}\n\t}\n\n\tdirs := make([]string, size)\n\ti := 0\n\tfor dir := range pluginDirs {\n\t\tdirs[i] = dir\n\t\ti++\n\t}\n\n\tsort.Strings(dirs)\n\treturn dirs\n}\n"
  },
  {
    "path": "modules/hbs/cache/strategies.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cache\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/db\"\n\t\"github.com/toolkits/container/set\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n)\n\ntype SafeStrategies struct {\n\tsync.RWMutex\n\tM map[int]*model.Strategy\n}\n\nvar Strategies = &SafeStrategies{M: make(map[int]*model.Strategy)}\n\nfunc (this *SafeStrategies) GetMap() map[int]*model.Strategy {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.M\n}\n\nfunc (this *SafeStrategies) Init(tpls map[int]*model.Template) {\n\tm, err := db.QueryStrategies(tpls)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n\nfunc GetBuiltinMetrics(hostname string) ([]*model.BuiltinMetric, error) {\n\tret := []*model.BuiltinMetric{}\n\thid, exists := HostMap.GetID(hostname)\n\tif !exists {\n\t\treturn ret, nil\n\t}\n\n\tgids, exists := HostGroupsMap.GetGroupIds(hid)\n\tif !exists {\n\t\treturn ret, nil\n\t}\n\n\t// 根据gids，获取绑定的所有tids\n\ttidSet := set.NewIntSet()\n\tfor _, gid := range gids {\n\t\ttids, exists := GroupTemplates.GetTemplateIds(gid)\n\t\tif !exists {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, tid := range tids {\n\t\t\ttidSet.Add(tid)\n\t\t}\n\t}\n\n\ttidSlice := tidSet.ToSlice()\n\tif len(tidSlice) == 0 {\n\t\treturn ret, nil\n\t}\n\n\t// 继续寻找这些tid的ParentId\n\tallTpls := TemplateCache.GetMap()\n\tfor _, tid := range tidSlice {\n\t\tpids := ParentIds(allTpls, tid)\n\t\tfor _, pid := range pids {\n\t\t\ttidSet.Add(pid)\n\t\t}\n\t}\n\n\t// 终于得到了最终的tid列表\n\ttidSlice = tidSet.ToSlice()\n\n\t// 把tid列表用逗号拼接在一起\n\tcount := len(tidSlice)\n\ttidStrArr := make([]string, count)\n\tfor i := 0; i < count; i++ {\n\t\ttidStrArr[i] = strconv.Itoa(tidSlice[i])\n\t}\n\n\treturn db.QueryBuiltinMetrics(strings.Join(tidStrArr, \",\"))\n}\n\nfunc ParentIds(allTpls map[int]*model.Template, tid int) (ret []int) {\n\tdepth := 0\n\tfor {\n\t\tif tid <= 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif t, exists := allTpls[tid]; exists {\n\t\t\tret = append(ret, tid)\n\t\t\ttid = t.ParentId\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\n\t\tdepth++\n\t\tif depth == 10 {\n\t\t\tlog.Println(\"[ERROR] template inherit cycle. id:\", tid)\n\t\t\treturn []int{}\n\t\t}\n\t}\n\n\tsz := len(ret)\n\tif sz <= 1 {\n\t\treturn\n\t}\n\n\tdesc := make([]int, sz)\n\tfor i, item := range ret {\n\t\tj := sz - i - 1\n\t\tdesc[j] = item\n\t}\n\n\treturn desc\n}\n"
  },
  {
    "path": "modules/hbs/cache/templates.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cache\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/db\"\n\t\"sync\"\n)\n\n// 一个HostGroup对应多个Template\ntype SafeGroupTemplates struct {\n\tsync.RWMutex\n\tM map[int][]int\n}\n\nvar GroupTemplates = &SafeGroupTemplates{M: make(map[int][]int)}\n\nfunc (this *SafeGroupTemplates) GetTemplateIds(gid int) ([]int, bool) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\ttemplateIds, exists := this.M[gid]\n\treturn templateIds, exists\n}\n\nfunc (this *SafeGroupTemplates) Init() {\n\tm, err := db.QueryGroupTemplates()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n\ntype SafeTemplateCache struct {\n\tsync.RWMutex\n\tM map[int]*model.Template\n}\n\nvar TemplateCache = &SafeTemplateCache{M: make(map[int]*model.Template)}\n\nfunc (this *SafeTemplateCache) GetMap() map[int]*model.Template {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.M\n}\n\nfunc (this *SafeTemplateCache) Init() {\n\tts, err := db.QueryTemplates()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = ts\n}\n\ntype SafeHostTemplateIds struct {\n\tsync.RWMutex\n\tM map[int][]int\n}\n\nvar HostTemplateIds = &SafeHostTemplateIds{M: make(map[int][]int)}\n\nfunc (this *SafeHostTemplateIds) GetMap() map[int][]int {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.M\n}\n\nfunc (this *SafeHostTemplateIds) Init() {\n\tm, err := db.QueryHostTemplateIds()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n"
  },
  {
    "path": "modules/hbs/cfg.example.json",
    "content": "{\n    \"debug\": true,\n    \"database\": \"root:@tcp(127.0.0.1:3306)/falcon_portal?loc=Local&parseTime=true\",\n    \"hosts\": \"\",\n    \"maxConns\": 20,\n    \"maxIdle\": 100,\n    \"listen\": \":6030\",\n    \"trustable\": [\"\"],\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:6031\"\n    }\n}\n"
  },
  {
    "path": "modules/hbs/control",
    "content": "#!/bin/bash\n\nWORKSPACE=$(cd $(dirname $0)/; pwd)\ncd $WORKSPACE\n\nmkdir -p var\n\nmodule=hbs\napp=falcon-$module\nconf=cfg.json\npidfile=var/app.pid\nlogfile=var/app.log\n\nfunction check_pid() {\n    if [ -f $pidfile ];then\n        pid=`cat $pidfile`\n        if [ -n $pid ]; then\n            running=`ps -p $pid|grep -v \"PID TTY\" |wc -l`\n            return $running\n        fi\n    fi\n    return 0\n}\n\nfunction start() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running already, pid=\"\n        cat $pidfile\n        return 1\n    fi\n\n    nohup ./$app -c $conf &> $logfile &\n    echo $! > $pidfile\n    echo \"$app started..., pid=$!\"\n}\n\nfunction stop() {\n    pid=`cat $pidfile`\n    kill $pid\n    echo \"$app stopped...\"\n}\n\nfunction restart() {\n    stop\n    sleep 1\n    start\n}\n\nfunction status() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running, pid=\"\n        cat $pidfile\n    else\n        echo \"$app is stopped\"\n    fi\n}\n\nfunction tailf() {\n    tail -f $logfile\n}\n\nfunction build() {\n    go build\n    if [ $? -ne 0 ]; then\n        exit $?\n    fi\n    mv $module $app\n    ./$app -v\n}\n\nfunction pack() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-$version.tar.gz control cfg.example.json $app gitversion\n}\n\nfunction packbin() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-bin-$version.tar.gz $app gitversion\n}\n\nfunction help() {\n    echo \"$0 build|pack|packbin|start|stop|restart|status|tail\"\n}\n\nif [ \"$1\" == \"\" ]; then\n    help\nelif [ \"$1\" == \"stop\" ];then\n    stop\nelif [ \"$1\" == \"start\" ];then\n    start\nelif [ \"$1\" == \"restart\" ];then\n    restart\nelif [ \"$1\" == \"status\" ];then\n    status\nelif [ \"$1\" == \"tail\" ];then\n    tailf\nelif [ \"$1\" == \"build\" ];then\n    build\nelif [ \"$1\" == \"pack\" ];then\n    pack\nelif [ \"$1\" == \"packbin\" ];then\n    packbin\nelse\n    help\nfi\n"
  },
  {
    "path": "modules/hbs/db/agent.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/g\"\n\t\"log\"\n)\n\nfunc UpdateAgent(agentInfo *model.AgentUpdateInfo) {\n\tsql := \"\"\n\tif g.Config().Hosts == \"\" {\n\t\tsql = fmt.Sprintf(\n\t\t\t\"insert into host(hostname, ip, agent_version, plugin_version) values ('%s', '%s', '%s', '%s') on duplicate key update ip='%s', agent_version='%s', plugin_version='%s'\",\n\t\t\tagentInfo.ReportRequest.Hostname,\n\t\t\tagentInfo.ReportRequest.IP,\n\t\t\tagentInfo.ReportRequest.AgentVersion,\n\t\t\tagentInfo.ReportRequest.PluginVersion,\n\t\t\tagentInfo.ReportRequest.IP,\n\t\t\tagentInfo.ReportRequest.AgentVersion,\n\t\t\tagentInfo.ReportRequest.PluginVersion,\n\t\t)\n\t} else {\n\t\t// sync, just update\n\t\tsql = fmt.Sprintf(\n\t\t\t\"update host set ip='%s', agent_version='%s', plugin_version='%s' where hostname='%s'\",\n\t\t\tagentInfo.ReportRequest.IP,\n\t\t\tagentInfo.ReportRequest.AgentVersion,\n\t\t\tagentInfo.ReportRequest.PluginVersion,\n\t\t\tagentInfo.ReportRequest.Hostname,\n\t\t)\n\t}\n\n\t_, err := DB.Exec(sql)\n\tif err != nil {\n\t\tlog.Println(\"exec\", sql, \"fail\", err)\n\t}\n\n}\n"
  },
  {
    "path": "modules/hbs/db/db.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"database/sql\"\n\t_ \"github.com/go-sql-driver/mysql\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/g\"\n\t\"log\"\n)\n\nvar DB *sql.DB\n\nfunc Init() {\n\tvar err error\n\tDB, err = sql.Open(\"mysql\", g.Config().Database)\n\tif err != nil {\n\t\tlog.Fatalln(\"open db fail:\", err)\n\t}\n\n\tDB.SetMaxOpenConns(g.Config().MaxConns)\n\tDB.SetMaxIdleConns(g.Config().MaxIdle)\n\n\terr = DB.Ping()\n\tif err != nil {\n\t\tlog.Fatalln(\"ping db fail:\", err)\n\t}\n}\n"
  },
  {
    "path": "modules/hbs/db/expression.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"log\"\n\t\"strings\"\n)\n\nfunc QueryExpressions() (ret []*model.Expression, err error) {\n\tsql := \"select id, expression, func, op, right_value, max_step, priority, note, action_id from expression where action_id>0 and pause=0\"\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn ret, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\te := model.Expression{}\n\t\tvar exp string\n\t\terr = rows.Scan(\n\t\t\t&e.Id,\n\t\t\t&exp,\n\t\t\t&e.Func,\n\t\t\t&e.Operator,\n\t\t\t&e.RightValue,\n\t\t\t&e.MaxStep,\n\t\t\t&e.Priority,\n\t\t\t&e.Note,\n\t\t\t&e.ActionId,\n\t\t)\n\n\t\tif err != nil {\n\t\t\tlog.Println(\"WARN:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\te.Metric, e.Tags, err = parseExpression(exp)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, &e)\n\t}\n\n\treturn ret, nil\n}\n\nfunc parseExpression(exp string) (metric string, tags map[string]string, err error) {\n\tleft := strings.Index(exp, \"(\")\n\tright := strings.Index(exp, \")\")\n\ttagStrs := strings.TrimSpace(exp[left+1 : right])\n\n\tarr := strings.Fields(tagStrs)\n\tif len(arr) < 2 {\n\t\terr = fmt.Errorf(\"tag not enough. exp: %s\", exp)\n\t\treturn\n\t}\n\n\ttags = make(map[string]string)\n\tfor _, item := range arr {\n\t\tkv := strings.Split(item, \"=\")\n\t\tif len(kv) != 2 {\n\t\t\terr = fmt.Errorf(\"parse %s fail\", exp)\n\t\t\treturn\n\t\t}\n\t\ttags[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])\n\t}\n\n\tmetric, exists := tags[\"metric\"]\n\tif !exists {\n\t\terr = fmt.Errorf(\"no metric give of %s\", exp)\n\t\treturn\n\t}\n\n\tdelete(tags, \"metric\")\n\treturn\n}\n"
  },
  {
    "path": "modules/hbs/db/group.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"log\"\n)\n\nfunc QueryHostGroups() (map[int][]int, error) {\n\tm := make(map[int][]int)\n\n\tsql := \"select grp_id, host_id from grp_host\"\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn m, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar gid, hid int\n\t\terr = rows.Scan(&gid, &hid)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, exists := m[hid]; exists {\n\t\t\tm[hid] = append(m[hid], gid)\n\t\t} else {\n\t\t\tm[hid] = []int{gid}\n\t\t}\n\t}\n\n\treturn m, nil\n}\n"
  },
  {
    "path": "modules/hbs/db/host.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"log\"\n\t\"time\"\n)\n\nfunc QueryHosts() (map[string]int, error) {\n\tm := make(map[string]int)\n\n\tsql := \"select id, hostname from host\"\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn m, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tid       int\n\t\t\thostname string\n\t\t)\n\n\t\terr = rows.Scan(&id, &hostname)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tm[hostname] = id\n\t}\n\n\treturn m, nil\n}\n\nfunc QueryMonitoredHosts() (map[int]*model.Host, error) {\n\thosts := make(map[int]*model.Host)\n\tnow := time.Now().Unix()\n\tsql := fmt.Sprintf(\"select id, hostname from host where maintain_begin > %d or maintain_end < %d\", now, now)\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn hosts, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tt := model.Host{}\n\t\terr = rows.Scan(&t.Id, &t.Name)\n\t\tif err != nil {\n\t\t\tlog.Println(\"WARN:\", err)\n\t\t\tcontinue\n\t\t}\n\t\thosts[t.Id] = &t\n\t}\n\n\treturn hosts, nil\n}\n"
  },
  {
    "path": "modules/hbs/db/plugin.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"log\"\n)\n\nfunc QueryPlugins() (map[int][]string, error) {\n\tm := make(map[int][]string)\n\n\tsql := \"select grp_id, dir from plugin_dir\"\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn m, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tid  int\n\t\t\tdir string\n\t\t)\n\n\t\terr = rows.Scan(&id, &dir)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, exists := m[id]; exists {\n\t\t\tm[id] = append(m[id], dir)\n\t\t} else {\n\t\t\tm[id] = []string{dir}\n\t\t}\n\t}\n\n\treturn m, nil\n}\n"
  },
  {
    "path": "modules/hbs/db/strategy.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/container/set\"\n\t\"log\"\n\t\"strings\"\n\t\"time\"\n)\n\n// 获取所有的Strategy列表\nfunc QueryStrategies(tpls map[int]*model.Template) (map[int]*model.Strategy, error) {\n\tret := make(map[int]*model.Strategy)\n\n\tif tpls == nil || len(tpls) == 0 {\n\t\treturn ret, fmt.Errorf(\"illegal argument\")\n\t}\n\n\tnow := time.Now().Format(\"15:04\")\n\tsql := fmt.Sprintf(\n\t\t\"select %s from strategy as s where (s.run_begin='' and s.run_end='') \"+\n\t\t\t\"or (s.run_begin <= '%s' and s.run_end >= '%s')\"+\n\t\t\t\"or (s.run_begin > s.run_end and !(s.run_begin > '%s' and s.run_end < '%s'))\",\n\t\t\"s.id, s.metric, s.tags, s.func, s.op, s.right_value, s.max_step, s.priority, s.note, s.tpl_id\",\n\t\tnow,\n\t\tnow,\n\t\tnow,\n\t\tnow,\n\t)\n\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn ret, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\ts := model.Strategy{}\n\t\tvar tags string\n\t\tvar tid int\n\t\terr = rows.Scan(&s.Id, &s.Metric, &tags, &s.Func, &s.Operator, &s.RightValue, &s.MaxStep, &s.Priority, &s.Note, &tid)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\ttt := make(map[string]string)\n\n\t\tif tags != \"\" {\n\t\t\tarr := strings.Split(tags, \",\")\n\t\t\tfor _, tag := range arr {\n\t\t\t\tkv := strings.SplitN(tag, \"=\", 2)\n\t\t\t\tif len(kv) != 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\ttt[kv[0]] = kv[1]\n\t\t\t}\n\t\t}\n\n\t\ts.Tags = tt\n\t\ts.Tpl = tpls[tid]\n\t\tif s.Tpl == nil {\n\t\t\tlog.Printf(\"WARN: tpl is nil. strategy id=%d, tpl id=%d\", s.Id, tid)\n\t\t\t// 如果Strategy没有对应的Tpl，那就没有action，就没法报警，无需往后传递了\n\t\t\tcontinue\n\t\t}\n\n\t\tret[s.Id] = &s\n\t}\n\n\treturn ret, nil\n}\n\nfunc QueryBuiltinMetrics(tids string) ([]*model.BuiltinMetric, error) {\n\tsql := fmt.Sprintf(\n\t\t\"select metric, tags from strategy where tpl_id in (%s) and metric in ('net.port.listen', 'proc.num', 'du.bs', 'url.check.health')\",\n\t\ttids,\n\t)\n\n\tret := []*model.BuiltinMetric{}\n\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn ret, err\n\t}\n\n\tmetricTagsSet := set.NewStringSet()\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tbuiltinMetric := model.BuiltinMetric{}\n\t\terr = rows.Scan(&builtinMetric.Metric, &builtinMetric.Tags)\n\t\tif err != nil {\n\t\t\tlog.Println(\"WARN:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tk := fmt.Sprintf(\"%s%s\", builtinMetric.Metric, builtinMetric.Tags)\n\t\tif metricTagsSet.Exists(k) {\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, &builtinMetric)\n\t\tmetricTagsSet.Add(k)\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "modules/hbs/db/template.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage db\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"log\"\n)\n\nfunc QueryGroupTemplates() (map[int][]int, error) {\n\tm := make(map[int][]int)\n\n\tsql := \"select grp_id, tpl_id from grp_tpl\"\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn m, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar gid, tid int\n\t\terr = rows.Scan(&gid, &tid)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, exists := m[gid]; exists {\n\t\t\tm[gid] = append(m[gid], tid)\n\t\t} else {\n\t\t\tm[gid] = []int{tid}\n\t\t}\n\t}\n\n\treturn m, nil\n}\n\n// 获取所有的策略模板列表\nfunc QueryTemplates() (map[int]*model.Template, error) {\n\n\ttemplates := make(map[int]*model.Template)\n\n\tsql := \"select id, tpl_name, parent_id, action_id, create_user from tpl\"\n\trows, err := DB.Query(sql)\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn templates, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tt := model.Template{}\n\t\terr = rows.Scan(&t.Id, &t.Name, &t.ParentId, &t.ActionId, &t.Creator)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR:\", err)\n\t\t\tcontinue\n\t\t}\n\t\ttemplates[t.Id] = &t\n\t}\n\n\treturn templates, nil\n}\n\n// 一个机器ID对应了多个模板ID\nfunc QueryHostTemplateIds() (map[int][]int, error) {\n\tret := make(map[int][]int)\n\trows, err := DB.Query(\"select a.tpl_id, b.host_id from grp_tpl as a inner join grp_host as b on a.grp_id=b.grp_id\")\n\tif err != nil {\n\t\tlog.Println(\"ERROR:\", err)\n\t\treturn ret, err\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar tid, hid int\n\n\t\terr = rows.Scan(&tid, &hid)\n\t\tif err != nil {\n\t\t\tlog.Println(\"ERROR:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, ok := ret[hid]; ok {\n\t\t\tret[hid] = append(ret[hid], tid)\n\t\t} else {\n\t\t\tret[hid] = []int{tid}\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "modules/hbs/g/cfg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/toolkits/file\"\n\t\"log\"\n\t\"sync\"\n)\n\ntype HttpConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype GlobalConfig struct {\n\tDebug     bool        `json:\"debug\"`\n\tHosts     string      `json:\"hosts\"`\n\tDatabase  string      `json:\"database\"`\n\tMaxConns  int         `json:\"maxConns\"`\n\tMaxIdle   int         `json:\"maxIdle\"`\n\tListen    string      `json:\"listen\"`\n\tTrustable []string    `json:\"trustable\"`\n\tHttp      *HttpConfig `json:\"http\"`\n}\n\nvar (\n\tConfigFile string\n\tconfig     *GlobalConfig\n\tconfigLock = new(sync.RWMutex)\n)\n\nfunc Config() *GlobalConfig {\n\tconfigLock.RLock()\n\tdefer configLock.RUnlock()\n\treturn config\n}\n\nfunc ParseConfig(cfg string) {\n\tif cfg == \"\" {\n\t\tlog.Fatalln(\"use -c to specify configuration file\")\n\t}\n\n\tif !file.IsExist(cfg) {\n\t\tlog.Fatalln(\"config file:\", cfg, \"is not existent\")\n\t}\n\n\tConfigFile = cfg\n\n\tconfigContent, err := file.ToTrimString(cfg)\n\tif err != nil {\n\t\tlog.Fatalln(\"read config file:\", cfg, \"fail:\", err)\n\t}\n\n\tvar c GlobalConfig\n\terr = json.Unmarshal([]byte(configContent), &c)\n\tif err != nil {\n\t\tlog.Fatalln(\"parse config file:\", cfg, \"fail:\", err)\n\t}\n\n\tconfigLock.Lock()\n\tdefer configLock.Unlock()\n\n\tconfig = &c\n\n\tlog.Println(\"read config file:\", cfg, \"successfully\")\n}\n"
  },
  {
    "path": "modules/hbs/g/g.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"runtime\"\n)\n\n// change log:\n// 1.0.7: code refactor for open source\n// 1.0.8: bugfix loop init cache\n// 1.0.9: update host table anyway\n// 1.1.0: remove Checksum when query plugins\n\nvar (\n\tBinaryName string\n\tVersion    string\n\tGitCommit  string\n)\n\nfunc VersionMsg() string {\n\treturn Version + \"@\" + GitCommit\n}\n\nfunc init() {\n\truntime.GOMAXPROCS(runtime.NumCPU())\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)\n}\n"
  },
  {
    "path": "modules/hbs/http/common.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/g\"\n\t\"github.com/toolkits/file\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc configCommonRoutes() {\n\thttp.HandleFunc(\"/health\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"ok\"))\n\t})\n\n\thttp.HandleFunc(\"/version\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(g.VersionMsg()))\n\t})\n\n\thttp.HandleFunc(\"/workdir\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, file.SelfDir())\n\t})\n\n\thttp.HandleFunc(\"/config/reload\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif strings.HasPrefix(r.RemoteAddr, \"127.0.0.1\") {\n\t\t\tg.ParseConfig(g.ConfigFile)\n\t\t\tRenderDataJson(w, g.Config())\n\t\t} else {\n\t\t\tw.Write([]byte(\"no privilege\"))\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "modules/hbs/http/http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/g\"\n\t\"log\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n)\n\ntype Dto struct {\n\tMsg  string      `json:\"msg\"`\n\tData interface{} `json:\"data\"`\n}\n\nfunc init() {\n\tconfigCommonRoutes()\n\tconfigProcRoutes()\n}\n\nfunc RenderJson(w http.ResponseWriter, v interface{}) {\n\tbs, err := json.Marshal(v)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\tw.Write(bs)\n}\n\nfunc RenderDataJson(w http.ResponseWriter, data interface{}) {\n\tRenderJson(w, Dto{Msg: \"success\", Data: data})\n}\n\nfunc RenderMsgJson(w http.ResponseWriter, msg string) {\n\tRenderJson(w, map[string]string{\"msg\": msg})\n}\n\nfunc AutoRender(w http.ResponseWriter, data interface{}, err error) {\n\tif err != nil {\n\t\tRenderMsgJson(w, err.Error())\n\t\treturn\n\t}\n\tRenderDataJson(w, data)\n}\n\nfunc Start() {\n\tif !g.Config().Http.Enabled {\n\t\treturn\n\t}\n\n\taddr := g.Config().Http.Listen\n\tif addr == \"\" {\n\t\treturn\n\t}\n\ts := &http.Server{\n\t\tAddr:           addr,\n\t\tMaxHeaderBytes: 1 << 30,\n\t}\n\tlog.Println(\"http listening\", addr)\n\tlog.Fatalln(s.ListenAndServe())\n}\n"
  },
  {
    "path": "modules/hbs/http/proc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/cache\"\n\t\"net/http\"\n)\n\nfunc configProcRoutes() {\n\thttp.HandleFunc(\"/expressions\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, cache.ExpressionCache.Get())\n\t})\n\n\thttp.HandleFunc(\"/agents\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, cache.Agents.Keys())\n\t})\n\n\thttp.HandleFunc(\"/hosts\", func(w http.ResponseWriter, r *http.Request) {\n\t\tdata := make(map[string]*model.Host, len(cache.MonitoredHosts.Get()))\n\t\tfor k, v := range cache.MonitoredHosts.Get() {\n\t\t\tdata[fmt.Sprint(k)] = v\n\t\t}\n\t\tRenderDataJson(w, data)\n\t})\n\n\thttp.HandleFunc(\"/strategies\", func(w http.ResponseWriter, r *http.Request) {\n\t\tdata := make(map[string]*model.Strategy, len(cache.Strategies.GetMap()))\n\t\tfor k, v := range cache.Strategies.GetMap() {\n\t\t\tdata[fmt.Sprint(k)] = v\n\t\t}\n\t\tRenderDataJson(w, data)\n\t})\n\n\thttp.HandleFunc(\"/templates\", func(w http.ResponseWriter, r *http.Request) {\n\t\tdata := make(map[string]*model.Template, len(cache.TemplateCache.GetMap()))\n\t\tfor k, v := range cache.TemplateCache.GetMap() {\n\t\t\tdata[fmt.Sprint(k)] = v\n\t\t}\n\t\tRenderDataJson(w, data)\n\t})\n\n\thttp.HandleFunc(\"/plugins/\", func(w http.ResponseWriter, r *http.Request) {\n\t\thostname := r.URL.Path[len(\"/plugins/\"):]\n\t\tRenderDataJson(w, cache.GetPlugins(hostname))\n\t})\n\n}\n"
  },
  {
    "path": "modules/hbs/main.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/cache\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/db\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/http\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/rpc\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n)\n\nfunc main() {\n\tg.BinaryName = BinaryName\n\tg.Version = Version\n\tg.GitCommit = GitCommit\n\n\tcfg := flag.String(\"c\", \"cfg.json\", \"configuration file\")\n\tversion := flag.Bool(\"v\", false, \"show version\")\n\tflag.Parse()\n\n\tif *version {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\n\tg.ParseConfig(*cfg)\n\n\tdb.Init()\n\tcache.Init()\n\n\tgo cache.DeleteStaleAgents()\n\n\tgo http.Start()\n\tgo rpc.Start()\n\n\tsigs := make(chan os.Signal, 1)\n\tsignal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)\n\tgo func() {\n\t\t<-sigs\n\t\tfmt.Println()\n\t\tdb.DB.Close()\n\t\tos.Exit(0)\n\t}()\n\n\tselect {}\n}\n"
  },
  {
    "path": "modules/hbs/rpc/agent.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rpc\n\nimport (\n\t\"bytes\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/cache\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/g\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc (t *Agent) MinePlugins(args model.AgentHeartbeatRequest, reply *model.AgentPluginsResponse) error {\n\tif args.Hostname == \"\" {\n\t\treturn nil\n\t}\n\n\treply.Plugins = cache.GetPlugins(args.Hostname)\n\treply.Timestamp = time.Now().Unix()\n\n\treturn nil\n}\n\nfunc (t *Agent) ReportStatus(args *model.AgentReportRequest, reply *model.SimpleRpcResponse) error {\n\tif args.Hostname == \"\" {\n\t\treply.Code = 1\n\t\treturn nil\n\t}\n\n\tcache.Agents.Put(args)\n\n\treturn nil\n}\n\n// 需要checksum一下来减少网络开销？其实白名单通常只会有一个或者没有，无需checksum\nfunc (t *Agent) TrustableIps(args *model.NullRpcRequest, ips *string) error {\n\t*ips = strings.Join(g.Config().Trustable, \",\")\n\treturn nil\n}\n\n// agent按照server端的配置，按需采集的metric，比如net.port.listen port=22 或者 proc.num name=zabbix_agentd\nfunc (t *Agent) BuiltinMetrics(args *model.AgentHeartbeatRequest, reply *model.BuiltinMetricResponse) error {\n\tif args.Hostname == \"\" {\n\t\treturn nil\n\t}\n\n\tmetrics, err := cache.GetBuiltinMetrics(args.Hostname)\n\tif err != nil {\n\t\treturn nil\n\t}\n\n\tchecksum := \"\"\n\tif len(metrics) > 0 {\n\t\tchecksum = DigestBuiltinMetrics(metrics)\n\t}\n\n\tif args.Checksum == checksum {\n\t\treply.Metrics = []*model.BuiltinMetric{}\n\t} else {\n\t\treply.Metrics = metrics\n\t}\n\treply.Checksum = checksum\n\treply.Timestamp = time.Now().Unix()\n\n\treturn nil\n}\n\nfunc DigestBuiltinMetrics(items []*model.BuiltinMetric) string {\n\tsort.Sort(model.BuiltinMetricSlice(items))\n\n\tvar buf bytes.Buffer\n\tfor _, m := range items {\n\t\tbuf.WriteString(m.String())\n\t}\n\n\treturn utils.Md5(buf.String())\n}\n"
  },
  {
    "path": "modules/hbs/rpc/hbs.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rpc\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/cache\"\n)\n\nfunc (t *Hbs) GetExpressions(req model.NullRpcRequest, reply *model.ExpressionResponse) error {\n\treply.Expressions = cache.ExpressionCache.Get()\n\treturn nil\n}\n\nfunc (t *Hbs) GetStrategies(req model.NullRpcRequest, reply *model.StrategiesResponse) error {\n\treply.HostStrategies = []*model.HostStrategy{}\n\t// 一个机器ID对应多个模板ID\n\thidTids := cache.HostTemplateIds.GetMap()\n\tsz := len(hidTids)\n\tif sz == 0 {\n\t\treturn nil\n\t}\n\n\t// Judge需要的是hostname，此处要把HostId转换为hostname\n\t// 查出的hosts，是不处于维护时间内的\n\thosts := cache.MonitoredHosts.Get()\n\tif len(hosts) == 0 {\n\t\t// 所有机器都处于维护状态，汗\n\t\treturn nil\n\t}\n\n\ttpls := cache.TemplateCache.GetMap()\n\tif len(tpls) == 0 {\n\t\treturn nil\n\t}\n\n\tstrategies := cache.Strategies.GetMap()\n\tif len(strategies) == 0 {\n\t\treturn nil\n\t}\n\n\t// 做个索引，给一个tplId，可以很方便的找到对应了哪些Strategy\n\ttpl2Strategies := Tpl2Strategies(strategies)\n\n\thostStrategies := make([]*model.HostStrategy, 0, sz)\n\tfor hostId, tplIds := range hidTids {\n\n\t\th, exists := hosts[hostId]\n\t\tif !exists {\n\t\t\tcontinue\n\t\t}\n\n\t\t// 计算当前host配置了哪些监控策略\n\t\tss := CalcInheritStrategies(tpls, tplIds, tpl2Strategies)\n\t\tif len(ss) <= 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\ths := model.HostStrategy{\n\t\t\tHostname:   h.Name,\n\t\t\tStrategies: ss,\n\t\t}\n\n\t\thostStrategies = append(hostStrategies, &hs)\n\n\t}\n\n\treply.HostStrategies = hostStrategies\n\treturn nil\n}\n\nfunc Tpl2Strategies(strategies map[int]*model.Strategy) map[int][]*model.Strategy {\n\tret := make(map[int][]*model.Strategy)\n\tfor _, s := range strategies {\n\t\tif s == nil || s.Tpl == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif _, exists := ret[s.Tpl.Id]; exists {\n\t\t\tret[s.Tpl.Id] = append(ret[s.Tpl.Id], s)\n\t\t} else {\n\t\t\tret[s.Tpl.Id] = []*model.Strategy{s}\n\t\t}\n\t}\n\treturn ret\n}\n\nfunc CalcInheritStrategies(allTpls map[int]*model.Template, tids []int, tpl2Strategies map[int][]*model.Strategy) []model.Strategy {\n\t// 根据模板的继承关系，找到每个机器对应的模板全量\n\t/**\n\t * host_id =>\n\t * |a |d |a |a |a |\n\t * |  |  |b |b |f |\n\t * |  |  |  |c |  |\n\t * |  |  |  |  |  |\n\t */\n\ttpl_buckets := [][]int{}\n\tfor _, tid := range tids {\n\t\tids := cache.ParentIds(allTpls, tid)\n\t\tif len(ids) <= 0 {\n\t\t\tcontinue\n\t\t}\n\t\ttpl_buckets = append(tpl_buckets, ids)\n\t}\n\n\t// 每个host 关联的模板，有继承关系的放到同一个bucket中，其他的放在各自单独的bucket中\n\t/**\n\t * host_id =>\n\t * |a |d |a |\n\t * |b |  |f |\n\t * |c |  |  |\n\t * |  |  |  |\n\t */\n\tcount := len(tpl_buckets)\n\tuniq_tpl_buckets := [][]int{}\n\tfor i := 0; i < count; i++ {\n\t\tvar valid bool = true\n\t\tfor j := 0; j < count; j++ {\n\t\t\tif i == j {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif slice_int_eq(tpl_buckets[i], tpl_buckets[j]) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif slice_int_lt(tpl_buckets[i], tpl_buckets[j]) {\n\t\t\t\tvalid = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif valid {\n\t\t\tuniq_tpl_buckets = append(uniq_tpl_buckets, tpl_buckets[i])\n\t\t}\n\t}\n\n\t// 继承覆盖父模板策略，得到每个模板聚合后的策略列表\n\tstrategies := []model.Strategy{}\n\n\texists_by_id := make(map[int]struct{})\n\tfor _, bucket := range uniq_tpl_buckets {\n\n\t\t// 开始计算一个桶，先计算老的tid，再计算新的，所以可以覆盖\n\t\t// 该桶最终结果\n\t\tbucket_stras_map := make(map[string][]*model.Strategy)\n\t\tfor _, tid := range bucket {\n\n\t\t\t// 一个tid对应的策略列表\n\t\t\tthe_tid_stras := make(map[string][]*model.Strategy)\n\n\t\t\tif stras, ok := tpl2Strategies[tid]; ok {\n\t\t\t\tfor _, s := range stras {\n\t\t\t\t\tuuid := fmt.Sprintf(\"metric:%s/tags:%v\", s.Metric, utils.SortedTags(s.Tags))\n\t\t\t\t\tif _, ok2 := the_tid_stras[uuid]; ok2 {\n\t\t\t\t\t\tthe_tid_stras[uuid] = append(the_tid_stras[uuid], s)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthe_tid_stras[uuid] = []*model.Strategy{s}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 覆盖父模板\n\t\t\tfor uuid, ss := range the_tid_stras {\n\t\t\t\tbucket_stras_map[uuid] = ss\n\t\t\t}\n\t\t}\n\n\t\tlast_tid := bucket[len(bucket)-1]\n\n\t\t// 替换所有策略的模板为最年轻的模板\n\t\tfor _, ss := range bucket_stras_map {\n\t\t\tfor _, s := range ss {\n\t\t\t\tvalStrategy := *s\n\t\t\t\t// exists_by_id[s.Id] 是根据策略ID去重，不太确定是否真的需要，不过加上肯定没问题\n\t\t\t\tif _, exist := exists_by_id[valStrategy.Id]; !exist {\n\t\t\t\t\tif valStrategy.Tpl.Id != last_tid {\n\t\t\t\t\t\tvalStrategy.Tpl = allTpls[last_tid]\n\t\t\t\t\t}\n\t\t\t\t\tstrategies = append(strategies, valStrategy)\n\t\t\t\t\texists_by_id[valStrategy.Id] = struct{}{}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn strategies\n}\n\nfunc slice_int_contains(list []int, target int) bool {\n\tfor _, b := range list {\n\t\tif b == target {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc slice_int_eq(a []int, b []int) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, av := range a {\n\t\tif av != b[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc slice_int_lt(a []int, b []int) bool {\n\tfor _, i := range a {\n\t\tif !slice_int_contains(b, i) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "modules/hbs/rpc/rpc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rpc\n\nimport (\n\t\"log\"\n\t\"net\"\n\t\"net/rpc\"\n\t\"net/rpc/jsonrpc\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/hbs/g\"\n)\n\ntype Hbs int\ntype Agent int\n\nfunc Start() {\n\taddr := g.Config().Listen\n\n\tserver := rpc.NewServer()\n\t// server.Register(new(filter.Filter))\n\tserver.Register(new(Agent))\n\tserver.Register(new(Hbs))\n\n\tl, e := net.Listen(\"tcp\", addr)\n\tif e != nil {\n\t\tlog.Fatalln(\"listen error:\", e)\n\t} else {\n\t\tlog.Println(\"listening\", addr)\n\t}\n\n\tfor {\n\t\tconn, err := l.Accept()\n\t\tif err != nil {\n\t\t\tlog.Println(\"listener accept fail:\", err)\n\t\t\ttime.Sleep(time.Duration(100) * time.Millisecond)\n\t\t\tcontinue\n\t\t}\n\t\tgo server.ServeCodec(jsonrpc.NewServerCodec(conn))\n\t}\n}\n"
  },
  {
    "path": "modules/hbs/version.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// build !release\npackage main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  },
  {
    "path": "modules/judge/.gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n*.swp\n*.swo\n*.log\n.idea\n.DS_Store\n/var\n/judge*\n/falcon-judge*\n/cfg.json\n/gitversion\n\n"
  },
  {
    "path": "modules/judge/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "modules/judge/NOTICE",
    "content": "Open-Falcon\n\nCopyright (c) 2014-2015 Xiaomi, Inc. All Rights Reserved.\n\nThis product is licensed to you under the Apache License, Version 2.0 (the \"License\").\nYou may not use this product except in compliance with the License.\n\nThis product may include a number of subcomponents with separate copyright notices\nand license terms. Your use of these subcomponents is subject to the terms and\nconditions of the subcomponent's license, as noted in the LICENSE file.\n"
  },
  {
    "path": "modules/judge/README.md",
    "content": "falcon-judge\n============\n\nJudge是用于判断是否触发报警条件的组件。\n\nTransfer的数据不但要打到Graph来存储并绘图，还要打到Judge用于报警判断。Judge先从hbs获取所有策略列表，静等Transfer的数据转发。\n每收到一条Transfer转发过来的数据，立即找到这条数据关联的Strategy、Expression，然后做阈值判断。\n\n**如何找到关联的Strategy**\npush上来的数据带有一个endpoint，endpoint通常都是hostname，hostname隶属于多个HostGroup，HostGroup可以关联多个Template，各个\nTeamplate下面就是Strategy，层层顺藤摸瓜可得。但是，如果endpoint不是hostname，并没有被HostGroup管理，那就找不到了。\n\n**如何找到关联的Expression**\n这是一种更通用的方案，主要针对endpoint不是hostname的情况。push上来的数据通常带有多个tag，比如project=falcon,module=judge，\n假如我们要针对所有打了project=falcon这个tag的数据做qps的阈值判断，那我们可以配置一个这样的表达式：\n\n```\neach(metric=qps project=falcon)\n```\n\n如上配置之后，push上来的数据如果发现metric=qps，并且带有project=falcon这个tag，那就说明与这个expression相关，要做相关阈值判断\n\n## Installation\n\n```bash\n# set $GOPATH and $GOROOT\nmkdir -p $GOPATH/src/github.com/open-falcon\ncd $GOPATH/src/github.com/open-falcon\ngit clone https://github.com/open-falcon/judge.git\ncd judge\ngo get ./...\n./control build\n./control start\n```\n\n## Configuration\n\n配置文件中主要是一些连接地址和监听的端口，没啥好说的，看一下alarm的配置，judge报警判断完毕之后会产生报警event，这些event会写入\nalarm的redis队列中，不同优先级（配置策略的时候每个策略会配置一个优先级，0-5）写入不同队列，alarm中除了redis地址需要修改，其他\n的建议维持默认。\n\nalarm中有一个minInterval的配置，单位是秒，默认是300秒，表示同一个event，如果配置报警多次，那么两个报警之间至少间隔300秒。\n这是个经验值，我们觉得报警太频繁没有意义，对工程师来说是干扰。收到报警之后拿出电脑、开机、连上vpn就差不多要3分钟了……\n\n"
  },
  {
    "path": "modules/judge/cfg.example.json",
    "content": "{\n    \"debug\": true,\n    \"debugHost\": \"nil\",\n    \"remain\": 11, \n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:6081\"\n    },\n    \"rpc\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:6080\"\n    },\n    \"hbs\": {\n        \"servers\": [\"127.0.0.1:6030\"],\n        \"timeout\": 300,\n        \"interval\": 60\n    },\n    \"alarm\": {\n        \"enabled\": true,\n        \"minInterval\": 300,\n        \"queuePattern\": \"event:p%v\",\n        \"redis\": {\n            \"dsn\": \"127.0.0.1:6379\",\n            \"maxIdle\": 5,\n            \"connTimeout\": 5000,\n            \"readTimeout\": 5000,\n            \"writeTimeout\": 5000\n        }\n    }\n}\n"
  },
  {
    "path": "modules/judge/control",
    "content": "#!/bin/bash\n\nWORKSPACE=$(cd $(dirname $0)/; pwd)\ncd $WORKSPACE\n\nmkdir -p var\n\nmodule=judge\napp=falcon-$module\nconf=cfg.json\npidfile=var/app.pid\nlogfile=var/app.log\n\n[[ -f $module ]] && mv $module $app\n[[ -f $conf ]] || cp cfg.example.json $conf\n\nfunction check_pid() {\n    if [ -f $pidfile ];then\n        pid=`cat $pidfile`\n        if [ -n $pid ]; then\n            running=`ps -p $pid|grep -v \"PID TTY\" |wc -l`\n            return $running\n        fi\n    fi\n    return 0\n}\n\nfunction start() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running already, pid=\"\n        cat $pidfile\n        return 1\n    fi\n\n    if [ $# -eq 2 ]; then\n        rpc=$1\n        http=$2\n        sed -i -e \"s/6080/${rpc}/g\" cfg.json\n        sed -i -e \"s/6081/${http}/g\" cfg.json\n    fi\n\n    nohup ./$app -c $conf >>$logfile 2>&1 &\n    echo $! > $pidfile\n    echo \"$app started..., pid=$!\"\n}\n\nfunction stop() {\n    pid=`cat $pidfile`\n    kill $pid\n    echo \"$app quit...\"\n}\n\nfunction kill9() {\n    pid=`cat $pidfile`\n    kill -9 $pid\n    echo \"$app stopped...\"\n}\n\nfunction restart() {\n    stop\n    sleep 1\n    start $1 $2\n}\n\nfunction status() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running, pid=\"\n        cat $pidfile\n    else\n        echo \"$app is stopped\"\n    fi\n}\n\nfunction tailf() {\n    tail -f $logfile\n}\n\nfunction build() {\n    go build\n    if [ $? -ne 0 ]; then\n        exit $?\n    fi\n    mv $module $app\n    ./$app -v\n}\n\nfunction pack() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-$version.tar.gz control $app cfg.example.json gitversion\n}\n\nfunction packbin() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-bin-$version.tar.gz $app gitversion\n}\n\nfunction help() {\n    echo \"$0 build|pack|packbin|start|stop|restart|status|tail\"\n}\n\nif [ \"$1\" == \"\" ]; then\n    help\nelif [ \"$1\" == \"stop\" ];then\n    stop\nelif [ \"$1\" == \"start\" ];then\n    start $2 $3\nelif [ \"$1\" == \"restart\" ];then\n    restart $2 $3\nelif [ \"$1\" == \"status\" ];then\n    status\nelif [ \"$1\" == \"tail\" ];then\n    tailf\nelif [ \"$1\" == \"build\" ];then\n    build\nelif [ \"$1\" == \"pack\" ];then\n    pack\nelif [ \"$1\" == \"packbin\" ];then\n    packbin\nelse\n    help\nfi\n"
  },
  {
    "path": "modules/judge/cron/cleaner.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/judge/store\"\n\t\"time\"\n)\n\nfunc CleanStale() {\n\tfor {\n\t\ttime.Sleep(time.Hour * 5)\n\t\tcleanStale()\n\t}\n}\n\nfunc cleanStale() {\n\tbefore := time.Now().Unix() - 3600*24*7\n\n\tarr := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}\n\tfor i := 0; i < 16; i++ {\n\t\tfor j := 0; j < 16; j++ {\n\t\t\tstore.HistoryBigMap[arr[i]+arr[j]].CleanStale(before)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/judge/cron/strategy.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage cron\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/g\"\n)\n\nfunc SyncStrategies() {\n\tduration := time.Duration(g.Config().Hbs.Interval) * time.Second\n\tfor {\n\t\tsyncStrategies()\n\t\tsyncExpression()\n\t\tsyncFilter()\n\t\ttime.Sleep(duration)\n\t}\n}\n\nfunc syncStrategies() {\n\tvar strategiesResponse model.StrategiesResponse\n\terr := g.HbsClient.Call(\"Hbs.GetStrategies\", model.NullRpcRequest{}, &strategiesResponse)\n\tif err != nil {\n\t\tlog.Println(\"[ERROR] Hbs.GetStrategies:\", err)\n\t\treturn\n\t}\n\n\trebuildStrategyMap(&strategiesResponse)\n}\n\nfunc rebuildStrategyMap(strategiesResponse *model.StrategiesResponse) {\n\t// endpoint:metric => [strategy1, strategy2 ...]\n\tm := make(map[string][]model.Strategy)\n\tfor _, hs := range strategiesResponse.HostStrategies {\n\t\thostname := hs.Hostname\n\t\tif g.Config().Debug && hostname == g.Config().DebugHost {\n\t\t\tlog.Println(hostname, \"strategies:\")\n\t\t\tbs, _ := json.Marshal(hs.Strategies)\n\t\t\tfmt.Println(string(bs))\n\t\t}\n\t\tfor _, strategy := range hs.Strategies {\n\t\t\tkey := fmt.Sprintf(\"%s/%s\", hostname, strategy.Metric)\n\t\t\tif _, exists := m[key]; exists {\n\t\t\t\tm[key] = append(m[key], strategy)\n\t\t\t} else {\n\t\t\t\tm[key] = []model.Strategy{strategy}\n\t\t\t}\n\t\t}\n\t}\n\n\tg.StrategyMap.ReInit(m)\n}\n\nfunc syncExpression() {\n\tvar expressionResponse model.ExpressionResponse\n\terr := g.HbsClient.Call(\"Hbs.GetExpressions\", model.NullRpcRequest{}, &expressionResponse)\n\tif err != nil {\n\t\tlog.Println(\"[ERROR] Hbs.GetExpressions:\", err)\n\t\treturn\n\t}\n\n\trebuildExpressionMap(&expressionResponse)\n}\n\nfunc rebuildExpressionMap(expressionResponse *model.ExpressionResponse) {\n\tm := make(map[string][]*model.Expression)\n\tfor _, exp := range expressionResponse.Expressions {\n\t\tfor k, v := range exp.Tags {\n\t\t\tkey := fmt.Sprintf(\"%s/%s=%s\", exp.Metric, k, v)\n\t\t\tif _, exists := m[key]; exists {\n\t\t\t\tm[key] = append(m[key], exp)\n\t\t\t} else {\n\t\t\t\tm[key] = []*model.Expression{exp}\n\t\t\t}\n\t\t}\n\t}\n\n\tg.ExpressionMap.ReInit(m)\n}\n\nfunc syncFilter() {\n\tm := make(map[string]string)\n\n\t//M map[string][]model.Strategy\n\tstrategyMap := g.StrategyMap.Get()\n\tfor _, strategies := range strategyMap {\n\t\tfor _, strategy := range strategies {\n\t\t\tm[strategy.Metric] = strategy.Metric\n\t\t}\n\t}\n\n\t//M map[string][]*model.Expression\n\texpressionMap := g.ExpressionMap.Get()\n\tfor _, expressions := range expressionMap {\n\t\tfor _, expression := range expressions {\n\t\t\tm[expression.Metric] = expression.Metric\n\t\t}\n\t}\n\n\tg.FilterMap.ReInit(m)\n}\n"
  },
  {
    "path": "modules/judge/g/cfg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/toolkits/file\"\n\t\"log\"\n\t\"sync\"\n)\n\ntype HttpConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype RpcConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype HbsConfig struct {\n\tServers  []string `json:\"servers\"`\n\tTimeout  int64    `json:\"timeout\"`\n\tInterval int64    `json:\"interval\"`\n}\n\ntype RedisConfig struct {\n\tDsn          string `json:\"dsn\"`\n\tMaxIdle      int    `json:\"maxIdle\"`\n\tConnTimeout  int    `json:\"connTimeout\"`\n\tReadTimeout  int    `json:\"readTimeout\"`\n\tWriteTimeout int    `json:\"writeTimeout\"`\n}\n\ntype AlarmConfig struct {\n\tEnabled      bool         `json:\"enabled\"`\n\tMinInterval  int64        `json:\"minInterval\"`\n\tQueuePattern string       `json:\"queuePattern\"`\n\tRedis        *RedisConfig `json:\"redis\"`\n}\n\ntype GlobalConfig struct {\n\tDebug     bool         `json:\"debug\"`\n\tDebugHost string       `json:\"debugHost\"`\n\tRemain    int          `json:\"remain\"`\n\tHttp      *HttpConfig  `json:\"http\"`\n\tRpc       *RpcConfig   `json:\"rpc\"`\n\tHbs       *HbsConfig   `json:\"hbs\"`\n\tAlarm     *AlarmConfig `json:\"alarm\"`\n}\n\nvar (\n\tConfigFile string\n\tconfig     *GlobalConfig\n\tconfigLock = new(sync.RWMutex)\n)\n\nfunc Config() *GlobalConfig {\n\tconfigLock.RLock()\n\tdefer configLock.RUnlock()\n\treturn config\n}\n\nfunc ParseConfig(cfg string) {\n\tif cfg == \"\" {\n\t\tlog.Fatalln(\"use -c to specify configuration file\")\n\t}\n\n\tif !file.IsExist(cfg) {\n\t\tlog.Fatalln(\"config file:\", cfg, \"is not existent\")\n\t}\n\n\tConfigFile = cfg\n\n\tconfigContent, err := file.ToTrimString(cfg)\n\tif err != nil {\n\t\tlog.Fatalln(\"read config file:\", cfg, \"fail:\", err)\n\t}\n\n\tvar c GlobalConfig\n\terr = json.Unmarshal([]byte(configContent), &c)\n\tif err != nil {\n\t\tlog.Fatalln(\"parse config file:\", cfg, \"fail:\", err)\n\t}\n\n\tconfigLock.Lock()\n\tdefer configLock.Unlock()\n\n\tconfig = &c\n\n\tlog.Println(\"read config file:\", cfg, \"successfully\")\n}\n"
  },
  {
    "path": "modules/judge/g/g.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"runtime\"\n)\n\n// change log\n// 2.0.1: bugfix HistoryData limit\n// 2.0.2: clean stale data\n// 2.0.3: add timeout to sync strategies and expressions\n\nvar (\n\tBinaryName string\n\tVersion    string\n\tGitCommit  string\n)\n\nfunc VersionMsg() string {\n\treturn Version + \"@\" + GitCommit\n}\n\nfunc init() {\n\truntime.GOMAXPROCS(runtime.NumCPU())\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)\n}\n"
  },
  {
    "path": "modules/judge/g/redis.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/garyburd/redigo/redis\"\n)\n\nvar RedisConnPool *redis.Pool\n\nfunc InitRedisConnPool() {\n\tif !Config().Alarm.Enabled {\n\t\treturn\n\t}\n\n\tauth, dsn := formatRedisAddr(Config().Alarm.Redis.Dsn)\n\tmaxIdle := Config().Alarm.Redis.MaxIdle\n\tidleTimeout := 240 * time.Second\n\n\tconnTimeout := time.Duration(Config().Alarm.Redis.ConnTimeout) * time.Millisecond\n\treadTimeout := time.Duration(Config().Alarm.Redis.ReadTimeout) * time.Millisecond\n\twriteTimeout := time.Duration(Config().Alarm.Redis.WriteTimeout) * time.Millisecond\n\n\tRedisConnPool = &redis.Pool{\n\t\tMaxIdle:     maxIdle,\n\t\tIdleTimeout: idleTimeout,\n\t\tDial: func() (redis.Conn, error) {\n\t\t\tc, err := redis.DialTimeout(\"tcp\", dsn, connTimeout, readTimeout, writeTimeout)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif auth != \"\" {\n\t\t\t\tif _, err := c.Do(\"AUTH\", auth); err != nil {\n\t\t\t\t\t_ = c.Close()\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn c, err\n\t\t},\n\t\tTestOnBorrow: PingRedis,\n\t}\n}\n\nfunc formatRedisAddr(addrConfig string) (string, string) {\n\tif redisAddr := strings.Split(addrConfig, \"@\"); len(redisAddr) == 1 {\n\t\treturn \"\", redisAddr[0]\n\t} else {\n\t\treturn strings.Join(redisAddr[0:len(redisAddr)-1], \"@\"), redisAddr[len(redisAddr)-1]\n\t}\n}\n\nfunc PingRedis(c redis.Conn, t time.Time) error {\n\t_, err := c.Do(\"ping\")\n\tif err != nil {\n\t\tlog.Println(\"[ERROR] ping redis fail\", err)\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "modules/judge/g/rpc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"errors\"\n\t\"github.com/toolkits/net\"\n\t\"log\"\n\t\"math\"\n\t\"net/rpc\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype SingleConnRpcClient struct {\n\tsync.Mutex\n\trpcClient   *rpc.Client\n\tRpcServers  []string\n\tTimeout     time.Duration\n\tCallTimeout time.Duration\n}\n\nfunc (this *SingleConnRpcClient) close() {\n\tif this.rpcClient != nil {\n\t\tthis.rpcClient.Close()\n\t\tthis.rpcClient = nil\n\t}\n}\n\nfunc (this *SingleConnRpcClient) insureConn() {\n\tif this.rpcClient != nil {\n\t\treturn\n\t}\n\n\tvar err error\n\tvar retry int = 1\n\n\tfor {\n\t\tif this.rpcClient != nil {\n\t\t\treturn\n\t\t}\n\n\t\tfor _, s := range this.RpcServers {\n\t\t\tthis.rpcClient, err = net.JsonRpcClient(\"tcp\", s, this.Timeout)\n\t\t\tif err == nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlog.Printf(\"dial %s fail: %s\", s, err)\n\t\t}\n\n\t\tif retry > 6 {\n\t\t\tretry = 1\n\t\t}\n\n\t\ttime.Sleep(time.Duration(math.Pow(2.0, float64(retry))) * time.Second)\n\n\t\tretry++\n\t}\n}\n\nfunc (this *SingleConnRpcClient) Call(method string, args interface{}, reply interface{}) error {\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tthis.insureConn()\n\n\tdone := make(chan error, 1)\n\tgo func() {\n\t\tdone <- this.rpcClient.Call(method, args, reply)\n\t}()\n\n\tvar err error\n\n\tselect {\n\tcase <-time.After(this.CallTimeout):\n\t\terr = errors.New(\"call hbs timeout\")\n\tcase err = <-done:\n\t}\n\n\tif err != nil {\n\t\tthis.close()\n\t}\n\n\treturn err\n}\n"
  },
  {
    "path": "modules/judge/g/var.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n)\n\ntype SafeStrategyMap struct {\n\tsync.RWMutex\n\t// endpoint:metric => [strategy1, strategy2 ...]\n\tM map[string][]model.Strategy\n}\n\ntype SafeExpressionMap struct {\n\tsync.RWMutex\n\t// metric:tag1 => [exp1, exp2 ...]\n\t// metric:tag2 => [exp1, exp2 ...]\n\tM map[string][]*model.Expression\n}\n\ntype SafeEventMap struct {\n\tsync.RWMutex\n\tM map[string]*model.Event\n}\n\ntype SafeFilterMap struct {\n\tsync.RWMutex\n\tM map[string]string\n}\n\nvar (\n\tHbsClient     *SingleConnRpcClient\n\tStrategyMap   = &SafeStrategyMap{M: make(map[string][]model.Strategy)}\n\tExpressionMap = &SafeExpressionMap{M: make(map[string][]*model.Expression)}\n\tLastEvents    = &SafeEventMap{M: make(map[string]*model.Event)}\n\tFilterMap     = &SafeFilterMap{M: make(map[string]string)}\n)\n\nfunc InitHbsClient() {\n\tHbsClient = &SingleConnRpcClient{\n\t\tRpcServers:  Config().Hbs.Servers,\n\t\tTimeout:     time.Duration(Config().Hbs.Timeout) * time.Millisecond,\n\t\tCallTimeout: time.Duration(3000) * time.Millisecond,\n\t}\n}\n\nfunc (this *SafeStrategyMap) ReInit(m map[string][]model.Strategy) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n\nfunc (this *SafeStrategyMap) Get() map[string][]model.Strategy {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.M\n}\n\nfunc (this *SafeExpressionMap) ReInit(m map[string][]*model.Expression) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n\nfunc (this *SafeExpressionMap) Get() map[string][]*model.Expression {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.M\n}\n\nfunc (this *SafeEventMap) Get(key string) (*model.Event, bool) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tevent, exists := this.M[key]\n\treturn event, exists\n}\n\nfunc (this *SafeEventMap) Set(key string, event *model.Event) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M[key] = event\n}\n\nfunc (this *SafeFilterMap) ReInit(m map[string]string) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M = m\n}\n\nfunc (this *SafeFilterMap) Exists(key string) bool {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tif _, ok := this.M[key]; ok {\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "modules/judge/http/common.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/judge/g\"\n\t\"github.com/toolkits/file\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc configCommonRoutes() {\n\thttp.HandleFunc(\"/health\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"ok\"))\n\t})\n\n\thttp.HandleFunc(\"/version\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(g.VersionMsg()))\n\t})\n\n\thttp.HandleFunc(\"/workdir\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, file.SelfDir())\n\t})\n\n\thttp.HandleFunc(\"/config/reload\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif strings.HasPrefix(r.RemoteAddr, \"127.0.0.1\") {\n\t\t\tg.ParseConfig(g.ConfigFile)\n\t\t\tRenderDataJson(w, g.Config())\n\t\t} else {\n\t\t\tw.Write([]byte(\"no privilege\"))\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "modules/judge/http/http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/g\"\n\t\"log\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n)\n\ntype Dto struct {\n\tMsg  string      `json:\"msg\"`\n\tData interface{} `json:\"data\"`\n}\n\nfunc init() {\n\tconfigCommonRoutes()\n\tconfigInfoRoutes()\n}\n\nfunc RenderJson(w http.ResponseWriter, v interface{}) {\n\tbs, err := json.Marshal(v)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\tw.Write(bs)\n}\n\nfunc RenderDataJson(w http.ResponseWriter, data interface{}) {\n\tRenderJson(w, Dto{Msg: \"success\", Data: data})\n}\n\nfunc RenderMsgJson(w http.ResponseWriter, msg string) {\n\tRenderJson(w, map[string]string{\"msg\": msg})\n}\n\nfunc AutoRender(w http.ResponseWriter, data interface{}, err error) {\n\tif err != nil {\n\t\tRenderMsgJson(w, err.Error())\n\t\treturn\n\t}\n\tRenderDataJson(w, data)\n}\n\nfunc Start() {\n\tif !g.Config().Http.Enabled {\n\t\treturn\n\t}\n\n\taddr := g.Config().Http.Listen\n\tif addr == \"\" {\n\t\treturn\n\t}\n\ts := &http.Server{\n\t\tAddr:           addr,\n\t\tMaxHeaderBytes: 1 << 30,\n\t}\n\tlog.Println(\"http listening\", addr)\n\tlog.Fatalln(s.ListenAndServe())\n}\n"
  },
  {
    "path": "modules/judge/http/info.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/store\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc configInfoRoutes() {\n\t// e.g. /strategy/lg-dinp-docker01.bj/cpu.idle\n\thttp.HandleFunc(\"/strategy/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/strategy/\"):]\n\t\tm := g.StrategyMap.Get()\n\t\tRenderDataJson(w, m[urlParam])\n\t})\n\n\t// e.g. /expression/net.port.listen/port=22\n\thttp.HandleFunc(\"/expression/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/expression/\"):]\n\t\tm := g.ExpressionMap.Get()\n\t\tRenderDataJson(w, m[urlParam])\n\t})\n\n\thttp.HandleFunc(\"/count\", func(w http.ResponseWriter, r *http.Request) {\n\t\tsum := 0\n\t\tarr := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}\n\t\tfor i := 0; i < 16; i++ {\n\t\t\tfor j := 0; j < 16; j++ {\n\t\t\t\tsum += store.HistoryBigMap[arr[i]+arr[j]].Len()\n\t\t\t}\n\t\t}\n\n\t\tout := fmt.Sprintf(\"total: %d\\n\", sum)\n\t\tw.Write([]byte(out))\n\t})\n\n\thttp.HandleFunc(\"/history/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/history/\"):]\n\t\tpk := utils.Md5(urlParam)\n\t\tL, exists := store.HistoryBigMap[pk[0:2]].Get(pk)\n\t\tif !exists || L.Len() == 0 {\n\t\t\tw.Write([]byte(\"not found\\n\"))\n\t\t\treturn\n\t\t}\n\n\t\tarr := []string{}\n\n\t\tdatas, _ := L.HistoryData(g.Config().Remain - 1)\n\t\tfor i := 0; i < len(datas); i++ {\n\t\t\tif datas[i] == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tstr := fmt.Sprintf(\n\t\t\t\t\"%d %s %v\\n\",\n\t\t\t\tdatas[i].Timestamp,\n\t\t\t\tutils.UnixTsFormat(datas[i].Timestamp),\n\t\t\t\tdatas[i].Value,\n\t\t\t)\n\t\t\tarr = append(arr, str)\n\t\t}\n\n\t\tw.Write([]byte(strings.Join(arr, \"\")))\n\t})\n\n}\n"
  },
  {
    "path": "modules/judge/main.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/cron\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/http\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/rpc\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/store\"\n\t\"os\"\n)\n\nfunc main() {\n\tg.BinaryName = BinaryName\n\tg.Version = Version\n\tg.GitCommit = GitCommit\n\n\tcfg := flag.String(\"c\", \"cfg.json\", \"configuration file\")\n\tversion := flag.Bool(\"v\", false, \"show version\")\n\tflag.Parse()\n\n\tif *version {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\n\tg.ParseConfig(*cfg)\n\n\tg.InitRedisConnPool()\n\tg.InitHbsClient()\n\n\tstore.InitHistoryBigMap()\n\n\tgo http.Start()\n\tgo rpc.Start()\n\n\tgo cron.SyncStrategies()\n\tgo cron.CleanStale()\n\n\tselect {}\n}\n"
  },
  {
    "path": "modules/judge/rpc/receiver.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rpc\n\nimport (\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/store\"\n)\n\ntype Judge int\n\nfunc (this *Judge) Ping(req model.NullRpcRequest, resp *model.SimpleRpcResponse) error {\n\treturn nil\n}\n\nfunc (this *Judge) Send(items []*model.JudgeItem, resp *model.SimpleRpcResponse) error {\n\tremain := g.Config().Remain\n\t// 把当前时间的计算放在最外层，是为了减少获取时间时的系统调用开销\n\tnow := time.Now().Unix()\n\tfor _, item := range items {\n\t\texists := g.FilterMap.Exists(item.Metric)\n\t\tif !exists {\n\t\t\tcontinue\n\t\t}\n\t\tpk := item.PrimaryKey()\n\t\tstore.HistoryBigMap[pk[0:2]].PushFrontAndMaintain(pk, item, remain, now)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "modules/judge/rpc/rpc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rpc\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/judge/g\"\n\t\"log\"\n\t\"net\"\n\t\"net/rpc\"\n)\n\nfunc Start() {\n\tif !g.Config().Rpc.Enabled {\n\t\treturn\n\t}\n\taddr := g.Config().Rpc.Listen\n\ttcpAddr, err := net.ResolveTCPAddr(\"tcp\", addr)\n\tif err != nil {\n\t\tlog.Fatalf(\"net.ResolveTCPAddr fail: %s\", err)\n\t}\n\n\tlistener, err := net.ListenTCP(\"tcp\", tcpAddr)\n\tif err != nil {\n\t\tlog.Fatalf(\"listen %s fail: %s\", addr, err)\n\t} else {\n\t\tlog.Println(\"rpc listening\", addr)\n\t}\n\n\trpc.Register(new(Judge))\n\n\tfor {\n\t\tconn, err := listener.Accept()\n\t\tif err != nil {\n\t\t\tlog.Printf(\"listener.Accept occur error: %s\", err)\n\t\t\tcontinue\n\t\t}\n\t\tgo rpc.ServeConn(conn)\n\t}\n}\n"
  },
  {
    "path": "modules/judge/store/func.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage store\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype Function interface {\n\tCompute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool)\n}\n\ntype MaxFunction struct {\n\tFunction\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\nfunc (this MaxFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tmax := vs[0].Value\n\tfor i := 1; i < this.Limit; i++ {\n\t\tif max < vs[i].Value {\n\t\t\tmax = vs[i].Value\n\t\t}\n\t}\n\n\tleftValue = max\n\tisTriggered = checkIsTriggered(leftValue, this.Operator, this.RightValue)\n\treturn\n}\n\ntype MinFunction struct {\n\tFunction\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\nfunc (this MinFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tmin := vs[0].Value\n\tfor i := 1; i < this.Limit; i++ {\n\t\tif min > vs[i].Value {\n\t\t\tmin = vs[i].Value\n\t\t}\n\t}\n\n\tleftValue = min\n\tisTriggered = checkIsTriggered(leftValue, this.Operator, this.RightValue)\n\treturn\n}\n\ntype AllFunction struct {\n\tFunction\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\nfunc (this AllFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tisTriggered = true\n\tfor i := 0; i < this.Limit; i++ {\n\t\tisTriggered = checkIsTriggered(vs[i].Value, this.Operator, this.RightValue)\n\t\tif !isTriggered {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tleftValue = vs[0].Value\n\treturn\n}\n\ntype LookupFunction struct {\n\tFunction\n\tNum        int\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\nfunc (this LookupFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tleftValue = vs[0].Value\n\n\tfor n, i := 0, 0; i < this.Limit; i++ {\n\t\tif checkIsTriggered(vs[i].Value, this.Operator, this.RightValue) {\n\t\t\tn++\n\t\t\tif n == this.Num {\n\t\t\t\tisTriggered = true\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\treturn\n}\n\ntype SumFunction struct {\n\tFunction\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\nfunc (this SumFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tsum := 0.0\n\tfor i := 0; i < this.Limit; i++ {\n\t\tsum += vs[i].Value\n\t}\n\n\tleftValue = sum\n\tisTriggered = checkIsTriggered(leftValue, this.Operator, this.RightValue)\n\treturn\n}\n\ntype AvgFunction struct {\n\tFunction\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\nfunc (this AvgFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tsum := 0.0\n\tfor i := 0; i < this.Limit; i++ {\n\t\tsum += vs[i].Value\n\t}\n\n\tleftValue = sum / float64(this.Limit)\n\tisTriggered = checkIsTriggered(leftValue, this.Operator, this.RightValue)\n\treturn\n}\n\ntype DiffFunction struct {\n\tFunction\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\n// 只要有一个点的diff触发阈值，就报警\nfunc (this DiffFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\t// 此处this.Limit要+1，因为通常说diff(#3)，是当前点与历史的3个点相比较\n\t// 然而最新点已经在linkedlist的第一个位置，所以……\n\tvs, isEnough = L.HistoryData(this.Limit + 1)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tif len(vs) == 0 {\n\t\tisEnough = false\n\t\treturn\n\t}\n\n\tfirst := vs[0].Value\n\n\tisTriggered = false\n\tfor i := 1; i < this.Limit+1; i++ {\n\t\t// diff是当前值减去历史值\n\t\tleftValue = first - vs[i].Value\n\t\tisTriggered = checkIsTriggered(leftValue, this.Operator, this.RightValue)\n\t\tif isTriggered {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn\n}\n\ntype StdDeviationFunction struct {\n\tFunction\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\n/*\n\t离群点检测函数，更多请参考3-sigma算法：https://en.wikipedia.org/wiki/68%E2%80%9395%E2%80%9399.7_rule\n\tstddev(#10) = 3 //取最新 **10** 个点的数据分别计算得到他们的标准差和均值，分别计为 σ 和 μ，其中当前值计为 X，那么当 X 落在区间 [μ-3σ, μ+3σ] 之外时则报警。\n*/\n\nfunc (this StdDeviationFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tif len(vs) == 0 {\n\t\tisEnough = false\n\t\treturn\n\t}\n\n\tleftValue = vs[0].Value\n\n\tvar datas []float64\n\tfor _, i := range vs {\n\t\tdatas = append(datas, i.Value)\n\t}\n\n\tisTriggered = false\n\n\tstd := utils.ComputeStdDeviation(datas)\n\tmean := utils.ComputeMean(datas)\n\n\tupperBound := mean + this.RightValue*std\n\tlowerBound := mean - this.RightValue*std\n\n\tif leftValue < lowerBound || leftValue > upperBound {\n\t\tisTriggered = true\n\t}\n\n\treturn\n}\n\n// pdiff(#3)\ntype PDiffFunction struct {\n\tFunction\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\nfunc (this PDiffFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit + 1)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tif len(vs) == 0 {\n\t\tisEnough = false\n\t\treturn\n\t}\n\n\tfirst := vs[0].Value\n\n\tisTriggered = false\n\tfor i := 1; i < this.Limit+1; i++ {\n\t\tif vs[i].Value == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tleftValue = (first - vs[i].Value) / vs[i].Value * 100.0\n\t\tisTriggered = checkIsTriggered(leftValue, this.Operator, this.RightValue)\n\t\tif isTriggered {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn\n}\n\n\n//            3\n//          ____\n//   3    /\n//  ____/\n//\n//\n//kpdiff(#3,3)  告警上面类似的数据模型，解决某个指标长期稳定，当指标变化并且是持续的情况下告警。原来的diff 跟pdiff是只要一个点变化就告警。\n//kpdiff(#3,3)  左边的3是指稳定数据走势的数据点，右边的3是指持续变化的数据点\n\ntype KPDiffFunction struct {\n\tFunction\n\tNum        int\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\nfunc (this KPDiffFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit + this.Num)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tif len(vs) == 0 {\n\t\tisEnough = false\n\t\treturn\n\t}\n\tfor i := 0; i < this.Num; i++ {\n\t\tisTriggered = false\n\t\tif vs[i].Value == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\t//kpdiff(#3,3) 全部右边的点都对全部左边的点相减，得到3*3个差，再将3*3个差值分别除以对应左边的点，得到3*3个商值，全部商值满足阈值则报警\n\t\tfor j := 0; j < this.Limit; j++ {\n\t\t\tleftValue = (vs[j].Value - vs[this.Limit + this.Num -1 -i].Value) / vs[j].Value * 100.0\n\t\t\tisTriggered = checkIsTriggered(leftValue, this.Operator, this.RightValue)\n\t\t\tif isTriggered == false {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif isTriggered == false {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\ntype KDiffFunction struct {\n\tFunction\n\tNum        int\n\tLimit      int\n\tOperator   string\n\tRightValue float64\n}\n\nfunc (this KDiffFunction) Compute(L *SafeLinkedList) (vs []*model.HistoryData, leftValue float64, isTriggered bool, isEnough bool) {\n\tvs, isEnough = L.HistoryData(this.Limit + this.Num)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tif len(vs) == 0 {\n\t\tisEnough = false\n\t\treturn\n\t}\n\tfor i := 0; i < this.Num; i++ {\n\t\tisTriggered = false\n\t\tif vs[i].Value == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tfor j := 0; j < this.Limit; j++ {\n\t\t\tleftValue = vs[j].Value - vs[this.Limit + this.Num -1 -i].Value\n\t\t\tisTriggered = checkIsTriggered(leftValue, this.Operator, this.RightValue)\n\t\t\tif isTriggered == false {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif isTriggered == false {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\nfunc atois(s string) (ret []int, err error) {\n\ta := strings.Split(s, \",\")\n\tret = make([]int, len(a))\n\tfor i, v := range a {\n\t\tret[i], err = strconv.Atoi(v)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\n// @str: e.g. all(#3) sum(#3) avg(#10) diff(#10) stddev(#10)\nfunc ParseFuncFromString(str string, operator string, rightValue float64) (fn Function, err error) {\n\tif str == \"\" {\n\t\treturn nil, fmt.Errorf(\"func can not be null!\")\n\t}\n\tidx := strings.Index(str, \"#\")\n\targs, err := atois(str[idx+1 : len(str)-1])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch str[:idx-1] {\n\tcase \"max\":\n\t\tfn = &MaxFunction{Limit: args[0], Operator: operator, RightValue: rightValue}\n\tcase \"min\":\n\t\tfn = &MinFunction{Limit: args[0], Operator: operator, RightValue: rightValue}\n\tcase \"all\":\n\t\tfn = &AllFunction{Limit: args[0], Operator: operator, RightValue: rightValue}\n\tcase \"sum\":\n\t\tfn = &SumFunction{Limit: args[0], Operator: operator, RightValue: rightValue}\n\tcase \"avg\":\n\t\tfn = &AvgFunction{Limit: args[0], Operator: operator, RightValue: rightValue}\n\tcase \"diff\":\n\t\tfn = &DiffFunction{Limit: args[0], Operator: operator, RightValue: rightValue}\n\tcase \"pdiff\":\n\t\tfn = &PDiffFunction{Limit: args[0], Operator: operator, RightValue: rightValue}\n\tcase \"lookup\":\n\t\tfn = &LookupFunction{Num: args[0], Limit: args[1], Operator: operator, RightValue: rightValue}\n\tcase \"stddev\":\n\t\tfn = &StdDeviationFunction{Limit: args[0], Operator: operator, RightValue: rightValue}\n\tcase \"kdiff\":\n\t\tfn = &KDiffFunction{Num: args[0], Limit: args[1], Operator: operator, RightValue: rightValue}\n\tcase \"kpdiff\":\n\t\tfn = &KPDiffFunction{Num: args[0], Limit: args[1], Operator: operator, RightValue: rightValue}\n\tdefault:\n\t\terr = fmt.Errorf(\"not_supported_method\")\n\t}\n\n\treturn\n}\n\nfunc checkIsTriggered(leftValue float64, operator string, rightValue float64) (isTriggered bool) {\n\tswitch operator {\n\tcase \"=\", \"==\":\n\t\tisTriggered = math.Abs(leftValue-rightValue) < 0.0001\n\tcase \"!=\":\n\t\tisTriggered = math.Abs(leftValue-rightValue) > 0.0001\n\tcase \"<\":\n\t\tisTriggered = leftValue < rightValue\n\tcase \"<=\":\n\t\tisTriggered = leftValue <= rightValue\n\tcase \">\":\n\t\tisTriggered = leftValue > rightValue\n\tcase \">=\":\n\t\tisTriggered = leftValue >= rightValue\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "modules/judge/store/history.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage store\n\nimport (\n\t\"container/list\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"sync\"\n)\n\ntype JudgeItemMap struct {\n\tsync.RWMutex\n\tM map[string]*SafeLinkedList\n}\n\nfunc NewJudgeItemMap() *JudgeItemMap {\n\treturn &JudgeItemMap{M: make(map[string]*SafeLinkedList)}\n}\n\nfunc (this *JudgeItemMap) Get(key string) (*SafeLinkedList, bool) {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tval, ok := this.M[key]\n\treturn val, ok\n}\n\nfunc (this *JudgeItemMap) Set(key string, val *SafeLinkedList) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tthis.M[key] = val\n}\n\nfunc (this *JudgeItemMap) Len() int {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn len(this.M)\n}\n\nfunc (this *JudgeItemMap) Delete(key string) {\n\tthis.Lock()\n\tdefer this.Unlock()\n\tdelete(this.M, key)\n}\n\nfunc (this *JudgeItemMap) BatchDelete(keys []string) {\n\tcount := len(keys)\n\tif count == 0 {\n\t\treturn\n\t}\n\n\tthis.Lock()\n\tdefer this.Unlock()\n\tfor i := 0; i < count; i++ {\n\t\tdelete(this.M, keys[i])\n\t}\n}\n\nfunc (this *JudgeItemMap) CleanStale(before int64) {\n\tkeys := []string{}\n\n\tthis.RLock()\n\tfor key, L := range this.M {\n\t\tfront := L.Front()\n\t\tif front == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif front.Value.(*model.JudgeItem).Timestamp < before {\n\t\t\tkeys = append(keys, key)\n\t\t}\n\t}\n\tthis.RUnlock()\n\n\tthis.BatchDelete(keys)\n}\n\nfunc (this *JudgeItemMap) PushFrontAndMaintain(key string, val *model.JudgeItem, maxCount int, now int64) {\n\tif linkedList, exists := this.Get(key); exists {\n\t\tneedJudge := linkedList.PushFrontAndMaintain(val, maxCount)\n\t\tif needJudge {\n\t\t\tJudge(linkedList, val, now)\n\t\t}\n\t} else {\n\t\tNL := list.New()\n\t\tNL.PushFront(val)\n\t\tsafeList := &SafeLinkedList{L: NL}\n\t\tthis.Set(key, safeList)\n\t\tJudge(safeList, val, now)\n\t}\n}\n\n// 这是个线程不安全的大Map，需要提前初始化好\nvar HistoryBigMap = make(map[string]*JudgeItemMap)\n\nfunc InitHistoryBigMap() {\n\tarr := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}\n\tfor i := 0; i < 16; i++ {\n\t\tfor j := 0; j < 16; j++ {\n\t\t\tHistoryBigMap[arr[i]+arr[j]] = NewJudgeItemMap()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/judge/store/judge.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage store\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/judge/g\"\n\t\"log\"\n)\n\nfunc Judge(L *SafeLinkedList, firstItem *model.JudgeItem, now int64) {\n\tCheckStrategy(L, firstItem, now)\n\tCheckExpression(L, firstItem, now)\n}\n\nfunc CheckStrategy(L *SafeLinkedList, firstItem *model.JudgeItem, now int64) {\n\tkey := fmt.Sprintf(\"%s/%s\", firstItem.Endpoint, firstItem.Metric)\n\tstrategyMap := g.StrategyMap.Get()\n\tstrategies, exists := strategyMap[key]\n\tif !exists {\n\t\treturn\n\t}\n\n\tfor _, s := range strategies {\n\t\t// 因为key仅仅是endpoint和metric，所以得到的strategies并不一定是与当前judgeItem相关的\n\t\t// 比如lg-dinp-docker01.bj配置了两个proc.num的策略，一个name=docker，一个name=agent\n\t\t// 所以此处要排除掉一部分\n\t\trelated := true\n\t\tfor tagKey, tagVal := range s.Tags {\n\t\t\tif myVal, exists := firstItem.Tags[tagKey]; !exists || myVal != tagVal {\n\t\t\t\trelated = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !related {\n\t\t\tcontinue\n\t\t}\n\n\t\tjudgeItemWithStrategy(L, s, firstItem, now)\n\t}\n}\n\nfunc judgeItemWithStrategy(L *SafeLinkedList, strategy model.Strategy, firstItem *model.JudgeItem, now int64) {\n\tfn, err := ParseFuncFromString(strategy.Func, strategy.Operator, strategy.RightValue)\n\tif err != nil {\n\t\tlog.Printf(\"[ERROR] parse func %s fail: %v. strategy id: %d\", strategy.Func, err, strategy.Id)\n\t\treturn\n\t}\n\n\thistoryData, leftValue, isTriggered, isEnough := fn.Compute(L)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tevent := &model.Event{\n\t\tId:         fmt.Sprintf(\"s_%d_%s\", strategy.Id, firstItem.PrimaryKey()),\n\t\tStrategy:   &strategy,\n\t\tEndpoint:   firstItem.Endpoint,\n\t\tLeftValue:  leftValue,\n\t\tEventTime:  firstItem.Timestamp,\n\t\tPushedTags: firstItem.Tags,\n\t}\n\n\tsendEventIfNeed(historyData, isTriggered, now, event, strategy.MaxStep)\n}\n\nfunc sendEvent(event *model.Event) {\n\t// update last event\n\tg.LastEvents.Set(event.Id, event)\n\n\tbs, err := json.Marshal(event)\n\tif err != nil {\n\t\tlog.Printf(\"json marshal event %v fail: %v\", event, err)\n\t\treturn\n\t}\n\n\t// send to redis\n\tredisKey := fmt.Sprintf(g.Config().Alarm.QueuePattern, event.Priority())\n\trc := g.RedisConnPool.Get()\n\tdefer rc.Close()\n\trc.Do(\"LPUSH\", redisKey, string(bs))\n}\n\nfunc CheckExpression(L *SafeLinkedList, firstItem *model.JudgeItem, now int64) {\n\tkeys := buildKeysFromMetricAndTags(firstItem)\n\tif len(keys) == 0 {\n\t\treturn\n\t}\n\n\t// expression可能会被多次重复处理，用此数据结构保证只被处理一次\n\thandledExpression := make(map[int]struct{})\n\n\texpressionMap := g.ExpressionMap.Get()\n\tfor _, key := range keys {\n\t\texpressions, exists := expressionMap[key]\n\t\tif !exists {\n\t\t\tcontinue\n\t\t}\n\n\t\trelated := filterRelatedExpressions(expressions, firstItem)\n\t\tfor _, exp := range related {\n\t\t\tif _, ok := handledExpression[exp.Id]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\thandledExpression[exp.Id] = struct{}{}\n\t\t\tjudgeItemWithExpression(L, exp, firstItem, now)\n\t\t}\n\t}\n}\n\nfunc buildKeysFromMetricAndTags(item *model.JudgeItem) (keys []string) {\n\tfor k, v := range item.Tags {\n\t\tkeys = append(keys, fmt.Sprintf(\"%s/%s=%s\", item.Metric, k, v))\n\t}\n\tkeys = append(keys, fmt.Sprintf(\"%s/endpoint=%s\", item.Metric, item.Endpoint))\n\treturn\n}\n\nfunc filterRelatedExpressions(expressions []*model.Expression, firstItem *model.JudgeItem) []*model.Expression {\n\tsize := len(expressions)\n\tif size == 0 {\n\t\treturn []*model.Expression{}\n\t}\n\n\texps := make([]*model.Expression, 0, size)\n\n\tfor _, exp := range expressions {\n\n\t\trelated := true\n\n\t\titemTagsCopy := firstItem.Tags\n\t\t// 注意：exp.Tags 中可能会有一个endpoint=xxx的tag\n\t\tif _, ok := exp.Tags[\"endpoint\"]; ok {\n\t\t\titemTagsCopy = copyItemTags(firstItem)\n\t\t}\n\n\t\tfor tagKey, tagVal := range exp.Tags {\n\t\t\tif myVal, exists := itemTagsCopy[tagKey]; !exists || myVal != tagVal {\n\t\t\t\trelated = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !related {\n\t\t\tcontinue\n\t\t}\n\n\t\texps = append(exps, exp)\n\t}\n\n\treturn exps\n}\n\nfunc copyItemTags(item *model.JudgeItem) map[string]string {\n\tret := make(map[string]string)\n\tret[\"endpoint\"] = item.Endpoint\n\tif item.Tags != nil && len(item.Tags) > 0 {\n\t\tfor k, v := range item.Tags {\n\t\t\tret[k] = v\n\t\t}\n\t}\n\treturn ret\n}\n\nfunc judgeItemWithExpression(L *SafeLinkedList, expression *model.Expression, firstItem *model.JudgeItem, now int64) {\n\tfn, err := ParseFuncFromString(expression.Func, expression.Operator, expression.RightValue)\n\tif err != nil {\n\t\tlog.Printf(\"[ERROR] parse func %s fail: %v. expression id: %d\", expression.Func, err, expression.Id)\n\t\treturn\n\t}\n\n\thistoryData, leftValue, isTriggered, isEnough := fn.Compute(L)\n\tif !isEnough {\n\t\treturn\n\t}\n\n\tevent := &model.Event{\n\t\tId:         fmt.Sprintf(\"e_%d_%s\", expression.Id, firstItem.PrimaryKey()),\n\t\tExpression: expression,\n\t\tEndpoint:   firstItem.Endpoint,\n\t\tLeftValue:  leftValue,\n\t\tEventTime:  firstItem.Timestamp,\n\t\tPushedTags: firstItem.Tags,\n\t}\n\n\tsendEventIfNeed(historyData, isTriggered, now, event, expression.MaxStep)\n\n}\n\nfunc sendEventIfNeed(historyData []*model.HistoryData, isTriggered bool, now int64, event *model.Event, maxStep int) {\n\tlastEvent, exists := g.LastEvents.Get(event.Id)\n\tif isTriggered {\n\t\tevent.Status = \"PROBLEM\"\n\t\tif !exists || lastEvent.Status[0] == 'O' {\n\t\t\t// 本次触发了阈值，之前又没报过警，得产生一个报警Event\n\t\t\tevent.CurrentStep = 1\n\n\t\t\t// 但是有些用户把最大报警次数配置成了0，相当于屏蔽了，要检查一下\n\t\t\tif maxStep == 0 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tsendEvent(event)\n\t\t\treturn\n\t\t}\n\n\t\t// 逻辑走到这里，说明之前Event是PROBLEM状态\n\t\tif lastEvent.CurrentStep >= maxStep {\n\t\t\t// 报警次数已经足够多，到达了最多报警次数了，不再报警\n\t\t\treturn\n\t\t}\n\n\t\tif historyData[len(historyData)-1].Timestamp <= lastEvent.EventTime {\n\t\t\t// 产生过报警的点，就不能再使用来判断了，否则容易出现一分钟报一次的情况\n\t\t\t// 只需要拿最后一个historyData来做判断即可，因为它的时间最老\n\t\t\treturn\n\t\t}\n\n\t\tif now-lastEvent.EventTime < g.Config().Alarm.MinInterval {\n\t\t\t// 报警不能太频繁，两次报警之间至少要间隔MinInterval秒，否则就不能报警\n\t\t\treturn\n\t\t}\n\n\t\tevent.CurrentStep = lastEvent.CurrentStep + 1\n\t\tsendEvent(event)\n\t} else {\n\t\t// 如果LastEvent是Problem，报OK，否则啥都不做\n\t\tif exists && lastEvent.Status[0] == 'P' {\n\t\t\tevent.Status = \"OK\"\n\t\t\tevent.CurrentStep = 1\n\t\t\tsendEvent(event)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "modules/judge/store/linkedlist.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage store\n\nimport (\n\t\"container/list\"\n\t\"github.com/open-falcon/falcon-plus/common/model\"\n\t\"sync\"\n)\n\ntype SafeLinkedList struct {\n\tsync.RWMutex\n\tL *list.List\n}\n\nfunc (this *SafeLinkedList) ToSlice() []*model.JudgeItem {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\tsz := this.L.Len()\n\tif sz == 0 {\n\t\treturn []*model.JudgeItem{}\n\t}\n\n\tret := make([]*model.JudgeItem, 0, sz)\n\tfor e := this.L.Front(); e != nil; e = e.Next() {\n\t\tret = append(ret, e.Value.(*model.JudgeItem))\n\t}\n\treturn ret\n}\n\n// @param limit 至多返回这些，如果不够，有多少返回多少\n// @return bool isEnough\nfunc (this *SafeLinkedList) HistoryData(limit int) ([]*model.HistoryData, bool) {\n\tif limit < 1 {\n\t\t// 其实limit不合法，此处也返回false吧，上层代码要注意\n\t\t// 因为false通常使上层代码进入异常分支，这样就统一了\n\t\treturn []*model.HistoryData{}, false\n\t}\n\n\tsize := this.Len()\n\tif size == 0 {\n\t\treturn []*model.HistoryData{}, false\n\t}\n\n\tfirstElement := this.Front()\n\tfirstItem := firstElement.Value.(*model.JudgeItem)\n\n\tvar vs []*model.HistoryData\n\tisEnough := true\n\n\tjudgeType := firstItem.JudgeType[0]\n\tif judgeType == 'G' || judgeType == 'g' {\n\t\tif size < limit {\n\t\t\t// 有多少获取多少\n\t\t\tlimit = size\n\t\t\tisEnough = false\n\t\t}\n\t\tvs = make([]*model.HistoryData, limit)\n\t\tvs[0] = &model.HistoryData{Timestamp: firstItem.Timestamp, Value: firstItem.Value}\n\t\ti := 1\n\t\tcurrentElement := firstElement\n\t\tfor i < limit {\n\t\t\tnextElement := currentElement.Next()\n\t\t\tvs[i] = &model.HistoryData{\n\t\t\t\tTimestamp: nextElement.Value.(*model.JudgeItem).Timestamp,\n\t\t\t\tValue:     nextElement.Value.(*model.JudgeItem).Value,\n\t\t\t}\n\t\t\ti++\n\t\t\tcurrentElement = nextElement\n\t\t}\n\t} else {\n\t\tif size < limit+1 {\n\t\t\tisEnough = false\n\t\t\tlimit = size - 1\n\t\t}\n\n\t\tvs = make([]*model.HistoryData, limit)\n\n\t\ti := 0\n\t\tcurrentElement := firstElement\n\t\tfor i < limit {\n\t\t\tnextElement := currentElement.Next()\n\t\t\tdiffVal := currentElement.Value.(*model.JudgeItem).Value - nextElement.Value.(*model.JudgeItem).Value\n\t\t\tdiffTs := currentElement.Value.(*model.JudgeItem).Timestamp - nextElement.Value.(*model.JudgeItem).Timestamp\n\t\t\tvs[i] = &model.HistoryData{\n\t\t\t\tTimestamp: currentElement.Value.(*model.JudgeItem).Timestamp,\n\t\t\t\tValue:     diffVal / float64(diffTs),\n\t\t\t}\n\t\t\ti++\n\t\t\tcurrentElement = nextElement\n\t\t}\n\t}\n\n\treturn vs, isEnough\n}\n\nfunc (this *SafeLinkedList) PushFront(v interface{}) *list.Element {\n\tthis.Lock()\n\tdefer this.Unlock()\n\treturn this.L.PushFront(v)\n}\n\n// @return needJudge 如果是false不需要做judge，因为新上来的数据不合法\nfunc (this *SafeLinkedList) PushFrontAndMaintain(v *model.JudgeItem, maxCount int) bool {\n\tthis.Lock()\n\tdefer this.Unlock()\n\n\tsz := this.L.Len()\n\tif sz > 0 {\n\t\t// 新push上来的数据有可能重复了，或者timestamp不对，这种数据要丢掉\n\t\tif v.Timestamp <= this.L.Front().Value.(*model.JudgeItem).Timestamp || v.Timestamp <= 0 {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tthis.L.PushFront(v)\n\n\tsz++\n\tif sz <= maxCount {\n\t\treturn true\n\t}\n\n\tdel := sz - maxCount\n\tfor i := 0; i < del; i++ {\n\t\tthis.L.Remove(this.L.Back())\n\t}\n\n\treturn true\n}\n\nfunc (this *SafeLinkedList) Front() *list.Element {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.L.Front()\n}\n\nfunc (this *SafeLinkedList) Len() int {\n\tthis.RLock()\n\tdefer this.RUnlock()\n\treturn this.L.Len()\n}\n"
  },
  {
    "path": "modules/judge/version.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// build !release\npackage main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  },
  {
    "path": "modules/nodata/.gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n*.swp\n*.swo\n*.log\n.idea\n.DS_Store\n/var\n/falcon-nodata*\n/cfg.json\n/test/build\n\ngitversion\n"
  },
  {
    "path": "modules/nodata/README.md",
    "content": "# nodata\n+ [需求定位](#需求定位)\n+ [系统设计](#系统设计)\n+ [系统安装](#系统安装)\n+ [用户手册](#用户手册)\n+ [系统运维](#系统运维)\n+ [常见问题](#常见问题)\n\nnodata用于检测监控数据的上报异常。nodata和实时报警judge模块协同工作，过程为: 配置了nodata的采集项超时未上报数据，nodata生成一条默认的模拟数据；用户配置相应的报警策略，收到mock数据就产生报警。采集项上报异常检测，作为judge模块的一个必要补充，能够使judge的实时报警功能更加可靠、完善。\n\n## 需求定位\nnodata只处理如下的用户需求，\n\n1. 监测\"特征采集项\"的上报异常\n2. 监测少量的、十分重要的采集项的上报异常\n\n这里的特征采集项，指的是，能够表征某一监控采集服务数据上报情况的单个采集项。例如，falcon-agent的agent.alive指标就是一个特征采集项，它能够说明agent是否正常存活，进而能够说明通过agent上报的监控数据是否正常。\n\nnodata所谓的异常，限定为 用户数据采集服务异常、falcon数据上报链路异常等，主要场景描述如下。nodata提供了[阻塞功能](#阻塞设置)，防止网络故障、falcon服务故障等导致的大面积误报警。\n\n**用户数据采集服务异常**\n\n+ 用户数据采集服务，异常终止\n+ 用户数据采集服务，与falcon数据收集器之间的通信链路异常，使得数据无法上报\n+ 用户数据采集服务，上报的数据格式错误\n\n**falcon数据上报链路异常**\n\n+ agent异常，无法接收用户的数据推送、无法主动采集监控数据\n+ agent与数据转发transfer之间通信异常\n\n\n\n> 从系统边界的描述可知，nodata只是为少数重要的采集指标而设计的。nodata处理的采集项的数量，不应该多于judge的十分之一，nodata的滥用将会给falcon的运维管理带来麻烦。\n\n## 系统设计\n#### 系统流图\n![nodata.flow](https://raw.githubusercontent.com/niean/niean.common.store/master/images/open-falcon/nodata/nodata.flow.png)\n\n#### 模块结构\n![nodata.module](https://raw.githubusercontent.com/niean/niean.common.store/master/images/open-falcon/nodata/nodata.module.png)\n\n#### 部署架构\n![nodata.deploy](https://raw.githubusercontent.com/niean/niean.common.store/master/images/open-falcon/nodata/nodata.deploy.png)\n\n## 系统安装\n\n#### 准备工作\nnodata服务正常运行，依赖如下准备工作:\n\n+ 确保已经建立mysql数据表falcon_portal.mockcfg。其中，[falcon_portal](https://github.com/open-falcon/scripts/blob/master/db_schema/portal-db-schema.sql)为portal组件的mysql数据库，mockcfg为存放nodata配置的数据表。mockcfg的建表语句，见[这里](https://github.com/nieanan/nodata/blob/master/scripts/nodata-db-schema.sql)。\n+ 确保[portal组件](https://github.com/open-falcon/portal)已经更新。portal组件中，新增了对nodata配置的UI支持。\n+ 确保query组件版本不低于```1.4.3```。\n+ 确保graph组件版本不低于```0.5.5```。\n\n#### 源码编译\n\n```bash\n# update common lib\ncd $GOPATH/src/github.com/open-falcon/common\ngit pull\n\n# compile nodata\ncd $GOPATH/src/github.com/open-falcon/nodata\ngo get ./...\n./control build\n./control pack\n```\n\n最后一步会pack出一个tar.gz的安装包，拿着这个包去部署服务即可。\n\n#### 服务部署\n服务部署，包括配置修改、启动服务、检验服务、停止服务等。这之前，需要将安装包解压到服务的部署目录下。\n\n```bash\n# 修改配置, 配置项含义见下文\nmv cfg.example.json cfg.json\nvim cfg.json\n\n# 启动服务\n./control start\n\n# 校验服务,这里假定服务开启了6090的http监听端口。检验结果为ok表明服务正常启动。\ncurl -s \"127.0.0.1:6090/health\"\n\n...\n# 停止服务\n./control stop\n\n```\n服务启动后，可以通过日志查看服务的运行状态，日志文件地址为./var/app.log。可以通过调试脚本```./scripts/debug```查看服务器的内部状态数据，如 运行 ```bash ./scripts/debug``` 可以得到服务器内部状态的统计信息。\n\n\n#### 配置说明\n配置文件默认为./cfg.json。默认情况下，安装包会有一个cfg.example.json的配置文件示例。各配置项的含义，如下\n\n```bash\n## Configuration\n{\n    \"debug\": true,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:6090\" #nodata的http服务监听地址\n    },\n    \"query\":{ #query组件相关的配置\n        \"connectTimeout\": 5000, #查询数据时http连接超时时间,单位ms\n        \"requestTimeout\": 30000, #查询数据时http请求处理超时时间,单位ms\n        \"queryAddr\": \"127.0.0.1:9966\" #query组件的http监听地址,一般形如\"domain.query.service:9966\"\n    },\n    \"config\": { #配置信息\n        \"enabled\": true,\n        \"dsn\": \"root:passwd@tcp(127.0.0.1:3306)/falcon_portal?loc=Local&parseTime=true&wait_timeout=604800\", #portal的数据库连接信息,默认数据库为falcon_portal\n        \"maxIdle\": 4 #mysql连接池空闲连接数\n    },\n    \"collector\":{ #nodata数据采集相关的配置\n        \"enabled\": true,\n        \"batch\": 200, #一次数据采集的条数,建议使用默认值\n        \"concurrent\": 10 #采集并发度,建议使用默认值\n    },\n    \"sender\":{ #nodata发送mock数据相关的配置\n        \"enabled\": true,\n        \"connectTimeout\": 5000, #发送数据时http连接超时时间,单位ms\n        \"requestTimeout\": 30000, #发送数据时http请求超时时间,单位ms\n        \"transferAddr\": \"127.0.0.1:6060\", #transfer的http监听地址,一般形如\"domain.transfer.service:6060\"\n        \"batch\": 500, #发送数据时,每包数据包含的监控数据条数\n        \"block\": { #nodata阻塞设置\n            \"enabled\": false, #是否开启阻塞功能.默认不开启此功能\n            \"threshold\": 32 #触发nodata阻塞操作的阈值上限.当配置了nodata的数据项,数据上报中断的百分比,大于此阈值上限时,nodata阻塞mock数据的发送\n        }\n    }\n}\n       \n```\n\n#### 阻塞设置\n出现以下情况时，nodata不应该引发大面积的报警:\n\n+ 由于核心网络故障，导致大部分的采集项上报异常\n+ 由于falcon自身服务故障，导致大量的采集项上报异常\n\nnodata采用\"阈值检测\"方法，简答的解决上述误报问题。nodata服务启动时，我们会为它配置一个阻塞阈值，nodata服务实时计算当前处于接收超时状态的监控数据项的百分比(简称异常百分比)，然后这个用异常百分比与预先配置的阻塞阈值进行比较。如果异常百分比大于阻塞阈值，nodata服务就会停止发送mock数据；反之，如果异常百分比不大于阻塞阈值，nodata服务则正常发送mock数据。\n\n我们举一个例子来进行说明。假设，我们配置的阻塞阈值为20，系统当前有1000个监控指标项配置了nodata报警。某一段时间，由于IDC核心网络故障，导致300个监控指标无法顺利push到falcon。nodata服务检测到，监控项异常百分比为`(300/1000)*100 = 30%`，这个取值大于我们预先设置的阈值`20%`，因此nodata服务停止发送mock数据、直到异常百分比再次降低至不大于`20%`。\n\n阻塞阈值，可以通过nodata配置文件选项`sender.block.threshold`来设置，用户可以手动更改配置文件来更新这个阻塞阈值。nodata可以通过Gauss过滤、动态拟合出这个阻塞阈值，这种方式适合于数据上报较稳定的场合，详情可咨询[Open-Falcon开发者团队](http://open-falcon.com/)。\n\n处于阻塞期间，所有的数据上报异常将会被忽略，有可能错过一些真实的异常、导致漏报。误报和漏报之间的权衡，需要用户酌情选择**是否开启阻塞功能**、**如何设置阻塞阈值**。\n\n## 用户手册\n使用Nodata，需要进行两个配置: Nodata配置 和 策略配置。下面，我们以一个例子，讲述如何使用Nodata提供的服务。\n\n#### 用户需求\n当机器分组`cop.xiaomi_owt.inf_pdl.falcon_service.task`下的所有机器，其采集指标 `agent.alive` 上报中断时，通知用户。\n\n#### Nodata配置\n进入Nodata配置主页，点击右上角的添加按钮，添加nodata配置。\n![nodata.config](https://raw.githubusercontent.com/niean/niean.common.store/master/images/open-falcon/nodata/nodata.config.open.png)\n\n进行完上述配置后，分组`cop.xiaomi_owt.inf_pdl.falcon_service.task`下的所有机器，其采集项 `agent.alive`上报中断后，nodata服务就会补发一个取值为 `-1.0`、agent.alive的监控数据给监控系统。\n\n#### 策略配置\n配置了Nodata后，如果有数据上报中断的情况，Nodata配置中的默认值就会被上报。我们可以针对这个默认值，设置报警；只要收到了默认值，就认为发生了数据上报的中断（如果你设置的默认值，可能与正常上报的数据相等，那么请修改你的Nodata配置、使默认值有别于正常值）。将此策略，绑定到分组`cop.xiaomi_owt.inf_pdl.falcon_service.task`即可。\n\n![nodata.judge](https://raw.githubusercontent.com/niean/niean.common.store/master/images/open-falcon/nodata/ndoata.strategy.png)\n\n#### 注意事项\n1. 配置名称name，要全局唯一。这是为了方便Nodata配置的管理。\n2. 监控实例endpoint, 可以是机器分组、机器名或者其他 这三种类型，只能选择其中的一种。同一类型，支持多个记录，但建议不超过5个，多条记录换行分割、每行一条记录。选择机器分组时，系统会帮忙展开成具体机器名，支持动态生效。监控实体不是机器名时，只能选择“其他”类型。\n3. 监控指标metric。\n4. 数据标签tags，多个tag要用逗号隔开。必须填写完整的tags串，因为nodata会按照此tags串，去完全匹配、筛选监控数指标项。\n5. 数据类型type，只支持原始值类型GAUGE。因为，nodata只应该监控 \"特征指标\"(如agent.alive)，\"特征指标\"都是GAUGE类型的。\n6. 采集周期step，单位是秒。必须填写 完整&真实step。该字段不完整 或者 不真实，将会导致nodata监控的误报、漏报。\n7. 补发值default，必须有别于上报的真实数据。比如，`cpu.idle`的取值范围是[0,100]，那么它的nodata默认取值 只能取小于0或者大于100的值。否则，会发生误报、漏报。\n\n## 系统运维\n#### 部署实践\n当前，nodata服务只支持单实例部署。nodata服务本身的资源消耗较少，单个实例可以满足绝大部分的需求。这里给一个参考值:\n\n|监控指标总量|接收监控数据qps|nodata监控指标量| nodata采集原始数据的qps| nodata发送mock数据的qps| nodata的CPU消耗|nodata的MEM消耗|nodata的带宽消耗|nodata的DISK消耗|\n|-----\t|:---:\t|:---:\t|:---:\t|:---:\t|:---:\t|:---:\t|:---:\t|:---:\t|\n|5000万|25万/s|1.4万\t|700/s\t|<50/s\t|<5%\t|70MB\t|<150KB\t|忽略\t|\n\n#### 自监控\nnodata服务为单实例部署、存在单点故障风险，需要做好自监控。具体的，请参考[Falcon自监控实践](http://blog.niean.name/2015/08/16/falcon-self-monitor-availability/)一文。\n\n## 常见问题\n#### 没有产生mock数据\n假设没有生效的机器为hostA，指标项为agent.alive，tags串为空。按照如下步骤进行问题排查:\n\n0.查看日志文件，检查nodata服务是否有异常、是否处于报警阻塞状态(\"nodata blocking\")等。nodata是否处于报警阻塞状态，可以查看日志文件中 是否有 \"nodata blocking\" 字样。默认的，nodata服务会关闭报警阻塞功能。报警阻塞的描述，见[这里](#阻塞设置)。\n\n1.查看，是否对该指标项，配置了nodata监控。如果没有配置nodata监控，需要先进行配置。\n\n运行如下指令 `./scripts/debug proc config/hostA/agent.alive`，返回结果分析如下:\n\n```bash\n# a. nodata配置正确\n{\n    \"data\": {\n        \"endpoint\": \"work\",\n        \"id\": 1,\n        \"metric\": \"agent.alive\",\n        \"mock\": -1,\n        \"name\": \"agent.alive.group\",\n        \"objType\": \"group\",\n        \"step\": 60,\n        \"tags\": {},\n        \"type\": \"GAUGE\"\n    },\n    \"msg\": \"success\"\n}\n\n# b. 该指标项没有配置nodata\n{\n    \"data\": {\n        \"endpoint\": \"\",\n        \"id\": 0,\n        \"metric\": \"\",\n        \"mock\": 0,\n        \"name\": \"\",\n        \"objType\": \"\",\n        \"step\": 0,\n        \"tags\": null,\n        \"type\": \"\"\n    },\n    \"msg\": \"success\"\n}\n```\n\n2.查看，是否采集了该指标项的数据。如果数据采集失败，请检查nodata服务的query地址配置是否正确、query组件是否正常工作等。\n\n运行指令`./scripts/debug proc collect/hostA/agent.alive`，结果如下:\n\n```bash\n# a. 数据采集正常: fstatus为OK，fts和ts相差不大于5min\n{\n    \"data\": \"ts:2015-10-23 12:45:00, value:1.000000, fts:2015-10-23 12:46:20, fstatus:OK\",\n    \"msg\": \"success\"\n}\n\n# b. 数据采集失败: fstatus不是OK，或者 fts和ts相差大于5min\n{\n    \"data\": \"ts:1970-01-01 00:00:00, value:0.000000, fts:1970-01-01 00:00:00, fstatus:\",\n    \"msg\": \"success\"\n}\n\n```\n\n3.查看，该指标项当前状态。如果处于NODATA状态，但是dashboard或者judge没有收到mock数据，请检查nodata服务的transfer地址配置是否正确、transfer服务数据上报服务是否正常等。\n\n运行命令`./scripts/debug proc status/hostA/agent.alive`，结果如下:\n\n```bash\n# a. 数据上报正常: Status为OK\n{\n    \"data\": {\n        \"Cnt\": 0,\n        \"Key\": \"hostA/agent.alive\",\n        \"Status\": \"OK\",\n        \"Ts\": 1445575800\n    },\n    \"msg\": \"success\"\n}\n\n# b. 数据上报中断: Status为NODATA\n{\r    \"data\": {\r        \"Cnt\": 17, \r        \"Key\": \"hostA/agent.alive\", \r        \"Status\": \"NODATA\", \r        \"Ts\": 1445576100\r    }, \r    \"msg\": \"success\"\r}\n\n```\n"
  },
  {
    "path": "modules/nodata/cfg.example.json",
    "content": "{\n    \"debug\": true,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:6090\"\n    },\n    \"plus_api\":{\n        \"connectTimeout\": 500,\n        \"requestTimeout\": 2000,\n        \"addr\": \"http://127.0.0.1:8080\",\n        \"token\": \"default-token-used-in-server-side\"\n    },\n    \"config\": {\n        \"enabled\": true,\n        \"dsn\": \"root:@tcp(127.0.0.1:3306)/falcon_portal?loc=Local&parseTime=true&wait_timeout=604800\",\n        \"maxIdle\": 4\n    },\n    \"collector\":{\n        \"enabled\": true,\n        \"batch\": 200,\n        \"concurrent\": 10\n    },\n    \"sender\":{\n        \"enabled\": true,\n        \"connectTimeout\": 500,\n        \"requestTimeout\": 2000,\n        \"transferAddr\": \"127.0.0.1:6060\",\n        \"batch\": 500\n    }\n}\n"
  },
  {
    "path": "modules/nodata/collector/collector.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage collector\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\ttlist \"github.com/toolkits/container/list\"\n\t\"github.com/toolkits/container/nmap\"\n\tttime \"github.com/toolkits/time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n)\n\n// 主动收集到的监控数据 的缓存\nvar (\n\t// map - list\n\tItemMap = nmap.NewSafeMap()\n)\n\nfunc Start() {\n\tif !g.Config().Collector.Enabled {\n\t\tlog.Println(\"collector.Start warning, not enabled\")\n\t\treturn\n\t}\n\n\tStartCollectorCron()\n\tlog.Println(\"collector.Start ok\")\n}\n\n// Interfaces Of ItemMap\nfunc GetFirstItem(key string) (*DataItem, bool) {\n\tlistv, found := ItemMap.Get(key)\n\tif !found || listv == nil {\n\t\treturn &DataItem{}, false\n\t}\n\n\tfirst := listv.(*tlist.SafeListLimited).Front()\n\tif first == nil {\n\t\treturn &DataItem{}, false\n\t}\n\n\treturn first.(*DataItem), true\n}\n\nfunc AddItem(key string, val *DataItem) {\n\tlistv, found := ItemMap.Get(key)\n\tif !found {\n\t\tll := tlist.NewSafeListLimited(3) //每个采集指标,缓存最新的3个数据点\n\t\tll.PushFrontViolently(val)\n\t\tItemMap.Put(key, ll)\n\t\treturn\n\t}\n\n\tlistv.(*tlist.SafeListLimited).PushFrontViolently(val)\n}\n\nfunc RemoveItem(key string) {\n\tItemMap.Remove(key)\n}\n\n// NoData Data Item Struct\ntype DataItem struct {\n\tTs      int64\n\tValue   float64\n\tFStatus string // OK|ERR\n\tFTs     int64\n}\n\nfunc NewDataItem(ts int64, val float64, fstatus string, fts int64) *DataItem {\n\treturn &DataItem{Ts: ts, Value: val, FStatus: fstatus, FTs: fts}\n}\n\nfunc (this *DataItem) String() string {\n\treturn fmt.Sprintf(\"ts:%s, value:%f, fts:%s, fstatus:%s\",\n\t\tttime.FormatTs(this.Ts), this.Value, ttime.FormatTs(this.FTs), this.FStatus)\n}\n"
  },
  {
    "path": "modules/nodata/collector/collector_cron.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage collector\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\ttsema \"github.com/toolkits/concurrent/semaphore\"\n\ttcron \"github.com/toolkits/cron\"\n\tttime \"github.com/toolkits/time\"\n\n\t\"github.com/open-falcon/falcon-plus/common/sdk/requests\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/config\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n\t\"github.com/toolkits/net/httplib\"\n)\n\nvar (\n\tcollectorCron = tcron.New()\n)\n\nfunc StartCollectorCron() {\n\tcollectorCron.AddFuncCC(\"*/20 * * * * ?\", func() {\n\t\tstart := time.Now().Unix()\n\t\tcnt := collectDataOnce()\n\t\tend := time.Now().Unix()\n\t\tif g.Config().Debug {\n\t\t\tlog.Printf(\"collect cron, cnt %d, time %ds, start %s\\n\", cnt, end-start, ttime.FormatTs(start))\n\t\t}\n\n\t\t// statistics\n\t\tg.CollectorCronCnt.Incr()\n\t\tg.CollectorLastTs.SetCnt(end - start)\n\t\tg.CollectorLastCnt.SetCnt(int64(cnt))\n\t\tg.CollectorCnt.IncrBy(int64(cnt))\n\t}, 1)\n\tcollectorCron.Start()\n}\n\nfunc CollectDataOnce() int {\n\treturn collectDataOnce()\n}\n\nfunc collectDataOnce() int {\n\tkeys := config.Keys()\n\tkeysLen := len(keys)\n\n\t// 并发+同步控制\n\tcfg := g.Config().Collector\n\tconcurrent := int(cfg.Concurrent)\n\tif concurrent < 1 || concurrent > 50 {\n\t\tconcurrent = 10\n\t}\n\tsema := tsema.NewSemaphore(concurrent)\n\n\tbatch := int(cfg.Batch)\n\tif batch < 100 || batch > 1000 {\n\t\tbatch = 200 //batch不能太小, 否则channel将会很大\n\t}\n\n\tbatchCnt := (keysLen + batch - 1) / batch\n\trch := make(chan int, batchCnt+1)\n\n\ti := 0\n\tfor i < keysLen {\n\t\tleftLen := keysLen - i\n\t\tfetchSize := batch // 每次处理batch个配置\n\t\tif leftLen < fetchSize {\n\t\t\tfetchSize = leftLen\n\t\t}\n\t\tfetchKeys := keys[i : i+fetchSize]\n\n\t\t// 并发collect数据\n\t\tsema.Acquire()\n\t\tgo func(keys []string, keySize int) {\n\t\t\tdefer sema.Release()\n\t\t\tsize, err := fetchItemsAndStore(keys, keySize)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"fetchItemAndStore fail, size:%v, error:%v\", size, err)\n\t\t\t}\n\t\t\tif g.Config().Debug {\n\t\t\t\tlog.Printf(\"fetchItemAndStore keys:%v, key_size:%v, ret_size:%v\", keys, keySize, size)\n\t\t\t}\n\t\t\trch <- size\n\t\t}(fetchKeys, fetchSize)\n\n\t\ti += fetchSize\n\t}\n\n\tcollectCnt := 0\n\tfor i := 0; i < batchCnt; i++ {\n\t\tselect {\n\t\tcase cnt := <-rch:\n\t\t\tcollectCnt += cnt\n\t\t}\n\t}\n\n\treturn collectCnt\n}\n\nfunc fetchItemsAndStore(fetchKeys []string, fetchSize int) (size int, errt error) {\n\tif fetchSize < 1 {\n\t\treturn\n\t}\n\n\t// form request args\n\targs := make([]*cmodel.GraphLastParam, 0)\n\tfor _, key := range fetchKeys {\n\t\tndcfg, found := config.GetNdConfig(key)\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\n\t\tendpoint := ndcfg.Endpoint\n\t\tcounter := cutils.Counter(ndcfg.Metric, ndcfg.Tags)\n\t\targ := &cmodel.GraphLastParam{endpoint, counter}\n\t\targs = append(args, arg)\n\t}\n\tif len(args) < 1 {\n\t\treturn\n\t}\n\n\tresp, err := queryLastPoints(args)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// store items\n\tfts := time.Now().Unix()\n\tfor _, glr := range resp {\n\t\t//log.Printf(\"collect:%v\\n\", glr)\n\t\tif glr == nil || glr.Value == nil {\n\t\t\tcontinue\n\t\t}\n\t\tAddItem(cutils.PK2(glr.Endpoint, glr.Counter), NewDataItem(glr.Value.Timestamp, float64(glr.Value.Value), \"OK\", fts))\n\t}\n\n\treturn len(resp), nil\n}\n\nfunc queryLastPoints(param []*cmodel.GraphLastParam) (resp []*cmodel.GraphLastResp, err error) {\n\tcfg := g.Config()\n\turi := fmt.Sprintf(\"%s/api/v1/graph/lastpoint\", cfg.PlusApi.Addr)\n\n\tvar req *httplib.BeegoHttpRequest\n\theaders := map[string]string{\"Content-type\": \"application/json\"}\n\treq, err = requests.CurlPlus(uri, \"POST\", \"nodata\", cfg.PlusApi.Token,\n\t\theaders, map[string]string{})\n\n\tif err != nil {\n\t\treturn\n\t}\n\treq.SetTimeout(time.Duration(cfg.PlusApi.ConnectTimeout)*time.Millisecond,\n\t\ttime.Duration(cfg.PlusApi.RequestTimeout)*time.Millisecond)\n\n\tb, err := json.Marshal(param)\n\tif err != nil {\n\t\treturn\n\t}\n\n\treq.Body(b)\n\n\terr = req.ToJson(&resp)\n\tif err != nil {\n\t\treturn\n\t}\n\n\treturn resp, nil\n}\n"
  },
  {
    "path": "modules/nodata/config/config.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage config\n\nimport (\n\t\"log\"\n\t\"sync\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/toolkits/container/nmap\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/config/service\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n)\n\n// nodata配置(mockcfg)的缓存, 这些数据来自配置中心\nvar (\n\trwlock      = sync.RWMutex{}\n\tNdConfigMap = nmap.NewSafeMap()\n)\n\nfunc Start() {\n\tif !g.Config().Config.Enabled {\n\t\tlog.Println(\"config.Start warning, not enabled\")\n\t\treturn\n\t}\n\n\tservice.InitDB()\n\tStartNdConfigCron()\n\tlog.Println(\"config.Start ok\")\n}\n\n// Interfaces Of StrategyMap\nfunc SetNdConfigMap(val *nmap.SafeMap) {\n\trwlock.Lock()\n\tdefer rwlock.Unlock()\n\n\tNdConfigMap = val\n}\n\nfunc Keys() []string {\n\trwlock.RLock()\n\tdefer rwlock.RUnlock()\n\treturn NdConfigMap.Keys()\n}\n\nfunc Size() int {\n\trwlock.RLock()\n\tdefer rwlock.RUnlock()\n\treturn NdConfigMap.Size()\n}\n\nfunc GetNdConfig(key string) (*cmodel.NodataConfig, bool) {\n\trwlock.RLock()\n\tdefer rwlock.RUnlock()\n\n\tval, found := NdConfigMap.Get(key)\n\tif found && val != nil {\n\t\treturn val.(*cmodel.NodataConfig), true\n\t}\n\treturn &cmodel.NodataConfig{}, false\n}\n"
  },
  {
    "path": "modules/nodata/config/config_cron.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage config\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/toolkits/container/nmap\"\n\ttcron \"github.com/toolkits/cron\"\n\tttime \"github.com/toolkits/time\"\n\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/config/service\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n)\n\nvar (\n\tndconfigCron     = tcron.New()\n\tndconfigCronSpec = \"50 */2 * * * ?\"\n)\n\nfunc StartNdConfigCron() {\n\tndconfigCron.AddFuncCC(ndconfigCronSpec, func() {\n\t\tstart := time.Now().Unix()\n\t\tcnt, _ := syncNdConfig()\n\t\tend := time.Now().Unix()\n\t\tif g.Config().Debug {\n\t\t\tlog.Printf(\"config cron, cnt %d, time %ds, start %s\\n\", cnt, end-start, ttime.FormatTs(start))\n\t\t}\n\n\t\t// statistics\n\t\tg.ConfigCronCnt.Incr()\n\t\tg.ConfigLastTs.SetCnt(end - start)\n\t\tg.ConfigLastCnt.SetCnt(int64(cnt))\n\t}, 1)\n\tndconfigCron.Start()\n}\n\nfunc SyncNdConfigOnce() int {\n\tcnt, _ := syncNdConfig()\n\treturn cnt\n}\n\nfunc syncNdConfig() (cnt int, errt error) {\n\t// get configs\n\tconfigs := service.GetMockCfgFromDB()\n\t// restruct\n\tnm := nmap.NewSafeMap()\n\tfor _, ndc := range configs {\n\t\tendpoint := ndc.Endpoint\n\t\tmetric := ndc.Metric\n\t\ttags := ndc.Tags\n\t\tif endpoint == \"\" {\n\t\t\tlog.Printf(\"bad config: %+v\\n\", ndc)\n\t\t\tcontinue\n\t\t}\n\t\tpk := cutils.PK(endpoint, metric, tags)\n\t\tnm.Put(pk, ndc)\n\t}\n\n\t// cache\n\tSetNdConfigMap(nm)\n\n\treturn nm.Size(), nil\n}\n"
  },
  {
    "path": "modules/nodata/config/service/db.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage service\n\nimport (\n\t\"database/sql\"\n\t_ \"github.com/go-sql-driver/mysql\"\n\t\"log\"\n\t\"sync\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n)\n\nconst (\n\tdbBaseConnName = \"db.base\"\n)\n\nvar (\n\tdbLock    = sync.RWMutex{}\n\tdbConnMap = make(map[string]*sql.DB)\n)\n\nfunc InitDB() {\n\t_, err := GetDbConn(dbBaseConnName)\n\tif err != nil {\n\t\tlog.Fatalln(\"config.InitDB error\", err)\n\t\treturn // never go here\n\t}\n\n\tlog.Println(\"config.InitDB ok\")\n}\n\nfunc GetBaseConn() (c *sql.DB, e error) {\n\treturn GetDbConn(dbBaseConnName)\n}\n\nfunc GetDbConn(connName string) (c *sql.DB, e error) {\n\tdbLock.Lock()\n\tdefer dbLock.Unlock()\n\n\tvar err error\n\tvar dbConn *sql.DB\n\tdbConn = dbConnMap[connName]\n\tif dbConn == nil {\n\t\tdbConn, err = makeDbConn()\n\t\tif err != nil {\n\t\t\tcloseDbConn(dbConn)\n\t\t\treturn nil, err\n\t\t}\n\t\tdbConnMap[connName] = dbConn\n\t}\n\n\terr = dbConn.Ping()\n\tif err != nil {\n\t\tcloseDbConn(dbConn)\n\t\tdelete(dbConnMap, connName)\n\t\treturn nil, err\n\t}\n\n\treturn dbConn, err\n}\n\n// internal\nfunc makeDbConn() (conn *sql.DB, err error) {\n\tconn, err = sql.Open(\"mysql\", g.Config().Config.Dsn)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconn.SetMaxIdleConns(int(g.Config().Config.MaxIdle))\n\terr = conn.Ping()\n\n\treturn conn, err\n}\n\nfunc closeDbConn(conn *sql.DB) {\n\tif conn != nil {\n\t\tconn.Close()\n\t}\n}\n"
  },
  {
    "path": "modules/nodata/config/service/host.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage service\n\nimport (\n\t\"log\"\n\t\"time\"\n)\n\n// FIX ME: too many JOIN\nfunc GetHostsFromGroup(grpName string) map[string]int {\n\thosts := make(map[string]int)\n\n\tnow := time.Now().Unix()\n\tsqlStatement := \"SELECT host.id, host.hostname FROM grp_host AS gh \" +\n\t\t\" INNER JOIN host ON host.id=gh.host_id AND (host.maintain_begin > ? OR host.maintain_end < ?)\" +\n\t\t\" INNER JOIN grp ON grp.id=gh.grp_id AND grp.grp_name=?\"\n\n\tdbConn, err := GetDbConn(\"nodata.host\")\n\tif err != nil {\n\t\tlog.Println(\"db.get_conn error, host\", err)\n\t\treturn hosts\n\t}\n\n\trows, err := dbConn.Query(sqlStatement, now, now, grpName)\n\tif err != nil {\n\t\tlog.Println(\"[ERROR]\", err)\n\t\treturn hosts\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\thid := -1\n\t\thostname := \"\"\n\t\terr = rows.Scan(&hid, &hostname)\n\t\tif err != nil {\n\t\t\tlog.Println(\"[ERROR]\", err)\n\t\t\tcontinue\n\t\t}\n\t\tif hid < 0 || hostname == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\thosts[hostname] = hid\n\t}\n\n\treturn hosts\n}\n"
  },
  {
    "path": "modules/nodata/config/service/mockcfg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage service\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n)\n\ntype MockCfg struct {\n\tId      int\n\tName    string\n\tObj     string\n\tObjType string\n\tMetric  string\n\tTags    map[string]string\n\tType    string\n\tStep    int64\n\tMock    float64\n}\n\n// 当 grp展开结果 与 host结果 存在冲突时, 优先选择 host结果\nfunc GetMockCfgFromDB() map[string]*cmodel.NodataConfig {\n\tret := make(map[string]*cmodel.NodataConfig)\n\n\tdbConn, err := GetDbConn(\"nodata.mockcfg\")\n\tif err != nil {\n\t\tlog.Println(\"db.get_conn error, mockcfg\", err)\n\t\treturn ret\n\t}\n\n\tq := fmt.Sprintf(\"SELECT id,name,obj,obj_type,metric,tags,dstype,step,mock FROM mockcfg\")\n\trows, err := dbConn.Query(q)\n\tif err != nil {\n\t\tlog.Println(\"db.query error, mockcfg\", err)\n\t\treturn ret\n\t}\n\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tt := MockCfg{}\n\t\ttags := \"\"\n\t\terr := rows.Scan(&t.Id, &t.Name, &t.Obj, &t.ObjType, &t.Metric, &tags, &t.Type, &t.Step, &t.Mock)\n\t\tif err != nil {\n\t\t\tlog.Println(\"db.scan error, mockcfg\", err)\n\t\t\tcontinue\n\t\t}\n\t\tt.Tags = cutils.DictedTagstring(tags)\n\n\t\terr = checkMockCfg(&t)\n\t\tif err != nil {\n\t\t\tlog.Println(\"check mockcfg, error:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tendpoints := getEndpoint(t.ObjType, t.Obj)\n\t\tif len(endpoints) < 1 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, ep := range endpoints {\n\t\t\tuuid := cutils.PK(ep, t.Metric, t.Tags)\n\t\t\tncfg := cmodel.NewNodataConfig(t.Id, t.Name, t.ObjType, ep, t.Metric, t.Tags, t.Type, t.Step, t.Mock)\n\n\t\t\tval, found := ret[uuid]\n\t\t\tif !found { // so cute, it's the first one\n\t\t\t\tret[uuid] = ncfg\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif isSpuerNodataCfg(val, ncfg) {\n\t\t\t\t// val is spuer than ncfg, so drop ncfg\n\t\t\t\tlog.Printf(\"nodata.mockcfg conflict, %s, used %s, drop %s\", uuid, val.Name, ncfg.Name)\n\t\t\t} else {\n\t\t\t\tret[uuid] = ncfg // overwrite the old one\n\t\t\t\tlog.Printf(\"nodata.mockcfg conflict, %s, used %s, drop %s\", uuid, ncfg.Name, val.Name)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc getEndpoint(objType string, obj string) []string {\n\tswitch objType {\n\tcase \"host\":\n\t\treturn getEndpointFromHosts(obj)\n\tcase \"group\":\n\t\treturn getEndpointFromGroups(obj)\n\tcase \"other\":\n\t\treturn getEndpointFromOther(obj)\n\tdefault:\n\t\treturn make([]string, 0)\n\t}\n}\n\nfunc getEndpointFromHosts(hosts string) []string {\n\tret := make([]string, 0)\n\n\thlist := strings.Split(hosts, \"\\n\")\n\tfor _, host := range hlist {\n\t\tnh := strings.TrimSpace(host)\n\t\tif nh != \"\" {\n\t\t\tret = append(ret, nh)\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc getEndpointFromGroups(grps string) []string {\n\tgrplist := strings.Split(grps, \"\\n\")\n\n\t// get host map, avoid duplicating\n\thosts := make(map[string]string)\n\tfor _, grp := range grplist {\n\t\tngrp := strings.TrimSpace(grp)\n\t\tif len(ngrp) < 1 {\n\t\t\tcontinue\n\t\t}\n\n\t\thostmap := GetHostsFromGroup(grp)\n\t\tfor hostname := range hostmap {\n\t\t\tif hostname != \"\" {\n\t\t\t\thosts[hostname] = hostname\n\t\t\t}\n\t\t}\n\t}\n\n\t// get host slice\n\tret := make([]string, 0)\n\tfor key := range hosts {\n\t\tret = append(ret, key)\n\t}\n\n\treturn ret\n}\n\nfunc getEndpointFromOther(other string) []string {\n\treturn getEndpointFromHosts(other)\n}\n\nfunc checkMockCfg(mc *MockCfg) error {\n\t// if len(mc.Endpoint) < 1 {\n\t// \treturn fmt.Errorf(\"bad mockcfg, endpoint empty\")\n\t// }\n\n\tif len(mc.Metric) < 1 {\n\t\treturn fmt.Errorf(\"bad mockcfg, metric empty\")\n\t}\n\n\tif mc.Type != \"GAUGE\" { // 只支持GAUGE类型\n\t\treturn fmt.Errorf(\"bad mockcfg, type illegal, type=%s\", mc.Type)\n\t}\n\n\tif mc.Step < 1 {\n\t\treturn fmt.Errorf(\"bad mockcfg, step illegal, step=%d\", mc.Step)\n\t}\n\n\treturn nil\n}\n\nfunc isSpuerNodataCfg(A *cmodel.NodataConfig, B *cmodel.NodataConfig) bool {\n\tif A.ObjType == \"group\" && B.ObjType == \"host\" {\n\t\treturn false\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "modules/nodata/control",
    "content": "#!/bin/bash\nworkspace=$(cd $(dirname $0) && pwd)\ncd $workspace\n\nmodule=nodata\napp=falcon-$module\nconf=cfg.json\npidfile=var/app.pid\nlogfile=var/app.log\n\nmkdir -p var &>/dev/null\n\n\n## build & pack\nfunction build() {\n    commit=$(git log -1 --pretty=%h)\n    cat <<EOF > ./g/git.go\npackage g\nconst (\n    COMMIT = \"$commit\"\n)\nEOF\n    go build -o $app main.go\n    sc=$?\n    if [ $sc -ne 0 ];then\n        echo \"build error\"\n        exit $sc\n    else\n        echo -n \"build ok, vsn=\" \n        ./$app -v \n    fi\n}\n\nfunction pack() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-$version.tar.gz control $app cfg.example.json gitversion ./scripts/debug\n    rm -f gitversion &>/dev/null\n}\n\nfunction packbin() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-bin-$version.tar.gz $app gitversion\n    rm -f gitversion &>/dev/null\n}\n\n## opt\nfunction start() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"started, pid=\"\n        cat $pidfile\n        return 1\n    fi\n\n    nohup ./$app -c $conf &> $logfile &\n    echo $! > $pidfile\n    echo \"start ok, pid=$!\"\n}\n\nfunction stop() {\n    pid=`cat $pidfile`\n    kill -9 $pid\n    echo \"stopped\"\n}\n\nfunction restart() {\n    stop\n    sleep 1\n    start\n}\n\n## other\nfunction status() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"running, pid=\"\n        cat $pidfile\n    else\n        echo \"stopped\"\n    fi\n}\n\nfunction version() {\n    ./$app -vg\n}\n\nfunction tailf() {\n    tail -f $logfile\n}\n\n## internal\nfunction check_pid() {\n    if [ -f $pidfile ];then\n        pid=`cat $pidfile`\n        if [ -n $pid ]; then\n            running=`ps -p $pid|grep -v \"PID TTY\" |wc -l`\n            return $running\n        fi\n    fi\n    return 0\n}\n\n## usage\nfunction usage() {\n    echo \"$0 build|pack|packbin|start|stop|restart|status|tail|version\"\n}\n\n## main\naction=$1\ncase $action in\n    ## build\n    \"build\" )\n        build\n        ;;\n    \"pack\" )\n        pack\n        ;;\n    \"packbin\" )\n        packbin\n        ;;\n    ## opt\n    \"start\" )\n        start\n        ;;\n    \"stop\" )\n        stop\n        ;;\n    \"restart\" )\n        restart\n        ;;\n    ## other\n    \"status\" )\n        status\n        ;;\n    \"version\" )\n        version\n        ;;\n    \"tail\" )\n        tailf\n        ;;\n    * )\n        usage\n        ;;\nesac\n"
  },
  {
    "path": "modules/nodata/g/cfg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/toolkits/file\"\n\t\"log\"\n\t\"sync\"\n)\n\ntype HttpConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype PlusAPIConfig struct {\n\tAddr           string `json:\"addr\"`\n\tToken          string `json:\"token\"`\n\tConnectTimeout int32  `json:\"connectTimeout\"`\n\tRequestTimeout int32  `json:\"requestTimeout\"`\n}\n\ntype NdConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tDsn     string `json:\"dsn\"`\n\tMaxIdle int32  `json:\"maxIdle\"`\n}\n\ntype CollectorConfig struct {\n\tEnabled    bool  `json:\"enabled\"`\n\tBatch      int32 `json:\"batch\"`\n\tConcurrent int32 `json:\"concurrent\"`\n}\n\ntype SenderConfig struct {\n\tEnabled        bool   `json:\"enabled\"`\n\tTransferAddr   string `json:\"transferAddr\"`\n\tConnectTimeout int32  `json:\"connectTimeout\"`\n\tRequestTimeout int32  `json:\"requestTimeout\"`\n\tBatch          int32  `json:\"batch\"`\n}\n\ntype GlobalConfig struct {\n\tDebug     bool             `json:\"debug\"`\n\tHttp      *HttpConfig      `json:\"http\"`\n\tPlusApi   *PlusAPIConfig   `json:\"plus_api\"`\n\tConfig    *NdConfig        `json:\"config\"`\n\tCollector *CollectorConfig `json:\"collector\"`\n\tSender    *SenderConfig    `json:\"sender\"`\n}\n\nvar (\n\tConfigFile string\n\tconfig     *GlobalConfig\n\tconfigLock = new(sync.RWMutex)\n)\n\nfunc Config() *GlobalConfig {\n\tconfigLock.RLock()\n\tdefer configLock.RUnlock()\n\treturn config\n}\n\nfunc ParseConfig(cfg string) {\n\tif cfg == \"\" {\n\t\tlog.Fatalln(\"use -c to specify configuration file\")\n\t}\n\n\tif !file.IsExist(cfg) {\n\t\tlog.Fatalln(\"config file:\", cfg, \"is not existent\")\n\t}\n\n\tConfigFile = cfg\n\n\tconfigContent, err := file.ToTrimString(cfg)\n\tif err != nil {\n\t\tlog.Fatalln(\"read config file:\", cfg, \"fail:\", err)\n\t}\n\n\tvar c GlobalConfig\n\terr = json.Unmarshal([]byte(configContent), &c)\n\tif err != nil {\n\t\tlog.Fatalln(\"g.ParseConfig error, parse config file\", cfg, \"fail,\", err)\n\t}\n\n\tconfigLock.Lock()\n\tdefer configLock.Unlock()\n\tconfig = &c\n\n\tlog.Println(\"g.ParseConfig ok, file \", cfg)\n}\n"
  },
  {
    "path": "modules/nodata/g/g.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"runtime\"\n)\n\n// changelog:\n// 0.0.1 init project\n// 0.0.2 make mock item.Ts one step after now(), rm sending log, add flood in proc\n// 0.0.3 mv common to falcon.common, simplify nodata's codes, mv cfgcenter to nodata\n// 0.0.4 fix bug of nil response on collecting from query\n// 0.0.5 collect items concurrently from query\n// 0.0.6 clear send buffer when blocking\n// 0.0.7 use gauss distribution to get threshold, sync judge and sender, fix bug of collector's cache\n// 0.0.8 simplify project\n\nvar (\n\tBinaryName string\n\tVersion    string\n\tGitCommit  string\n)\n\nfunc VersionMsg() string {\n\treturn Version + \"@\" + GitCommit\n}\n\nfunc init() {\n\truntime.GOMAXPROCS(runtime.NumCPU())\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)\n}\n"
  },
  {
    "path": "modules/nodata/g/git.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nconst (\n\tCOMMIT = \"12f7b3b\"\n)\n"
  },
  {
    "path": "modules/nodata/g/proc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\tnproc \"github.com/toolkits/proc\"\n\t\"log\"\n)\n\n// counter\nvar (\n\tConfigCronCnt = nproc.NewSCounterQps(\"ConfigCronCnt\")\n\tConfigLastTs  = nproc.NewSCounterBase(\"ConfigLastTs\")\n\tConfigLastCnt = nproc.NewSCounterBase(\"ConfigLastCnt\")\n\n\tCollectorCronCnt = nproc.NewSCounterQps(\"CollectorCronCnt\")\n\tCollectorLastTs  = nproc.NewSCounterBase(\"CollectorLastTs\")\n\tCollectorLastCnt = nproc.NewSCounterBase(\"CollectorLastCnt\")\n\tCollectorCnt     = nproc.NewSCounterQps(\"CollectorCnt\")\n\n\tJudgeCronCnt = nproc.NewSCounterQps(\"JudgeCronCnt\")\n\tJudgeLastTs  = nproc.NewSCounterBase(\"JudgeLastTs\")\n\n\tSenderCronCnt = nproc.NewSCounterQps(\"SenderCronCnt\")\n\tSenderLastTs  = nproc.NewSCounterBase(\"SenderLastTs\")\n\tSenderCnt     = nproc.NewSCounterQps(\"SenderCnt\")\n)\n\n// flood\nvar (\n\tFloodRate = nproc.NewSCounterBase(\"FloodRate\")\n\tThreshold = nproc.NewSCounterBase(\"Threshold\")\n\tBlocking  = nproc.NewSCounterBase(\"nodata.blocking\")\n)\n\nfunc StartProc() {\n\tlog.Println(\"g.StartProc ok\")\n}\n\nfunc GetAllCounters() []interface{} {\n\tret := make([]interface{}, 0)\n\n\tret = append(ret, ConfigCronCnt.Get())\n\tret = append(ret, ConfigLastTs.Get())\n\tret = append(ret, ConfigLastCnt.Get())\n\n\tret = append(ret, CollectorCronCnt.Get())\n\tret = append(ret, CollectorLastCnt.Get())\n\tret = append(ret, CollectorLastTs.Get())\n\tret = append(ret, CollectorCnt.Get())\n\n\tret = append(ret, JudgeCronCnt.Get())\n\tret = append(ret, JudgeLastTs.Get())\n\n\tret = append(ret, SenderCronCnt.Get())\n\tret = append(ret, SenderLastTs.Get())\n\tret = append(ret, SenderCnt.Get())\n\n\tret = append(ret, FloodRate.Get())\n\tret = append(ret, Threshold.Get())\n\tret = append(ret, Blocking.Get())\n\n\treturn ret\n}\n"
  },
  {
    "path": "modules/nodata/http/common.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/toolkits/file\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n)\n\nfunc configCommonRoutes() {\n\thttp.HandleFunc(\"/health\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"ok\\n\"))\n\t})\n\n\thttp.HandleFunc(\"/version\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(fmt.Sprintf(\"%s\\n\", g.VersionMsg())))\n\t})\n\n\thttp.HandleFunc(\"/workdir\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(fmt.Sprintf(\"%s\\n\", file.SelfDir())))\n\t})\n\n\thttp.HandleFunc(\"/config\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, g.Config())\n\t})\n\n\thttp.HandleFunc(\"/config/reload\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif strings.HasPrefix(r.RemoteAddr, \"127.0.0.1\") {\n\t\t\tg.ParseConfig(g.ConfigFile)\n\t\t\tRenderDataJson(w, \"ok\")\n\t\t} else {\n\t\t\tRenderDataJson(w, \"no privilege\")\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "modules/nodata/http/debug_http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/collector\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/config\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/sender\"\n)\n\nfunc configDebugHttpRoutes() {\n\thttp.HandleFunc(\"/debug/collector/collect\", func(w http.ResponseWriter, r *http.Request) {\n\t\tstart := time.Now().Unix()\n\t\tcnt := collector.CollectDataOnce()\n\t\tend := time.Now().Unix()\n\n\t\tret := make(map[string]int, 0)\n\t\tret[\"cnt\"] = cnt\n\t\tret[\"time\"] = int(end - start)\n\t\tRenderDataJson(w, ret)\n\t})\n\n\thttp.HandleFunc(\"/debug/config/sync\", func(w http.ResponseWriter, r *http.Request) {\n\t\tstart := time.Now().Unix()\n\t\tcnt := config.SyncNdConfigOnce()\n\t\tend := time.Now().Unix()\n\n\t\tret := make(map[string]int, 0)\n\t\tret[\"cnt\"] = cnt\n\t\tret[\"time\"] = int(end - start)\n\t\tRenderDataJson(w, ret)\n\t})\n\n\thttp.HandleFunc(\"/debug/sender/send\", func(w http.ResponseWriter, r *http.Request) {\n\t\tstart := time.Now().Unix()\n\t\tcnt := sender.SendMockOnce()\n\t\tend := time.Now().Unix()\n\n\t\tret := make(map[string]int, 0)\n\t\tret[\"cnt\"] = cnt\n\t\tret[\"time\"] = int(end - start)\n\t\tRenderDataJson(w, ret)\n\t})\n}\n"
  },
  {
    "path": "modules/nodata/http/http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n)\n\ntype Dto struct {\n\tMsg  string      `json:\"msg\"`\n\tData interface{} `json:\"data\"`\n}\n\nfunc Start() {\n\tgo startHttpServer()\n}\n\nfunc configRoutes() {\n\tconfigCommonRoutes()\n\tconfigProcHttpRoutes()\n\tconfigDebugHttpRoutes()\n}\n\nfunc startHttpServer() {\n\tif !g.Config().Http.Enabled {\n\t\treturn\n\t}\n\n\taddr := g.Config().Http.Listen\n\tif addr == \"\" {\n\t\treturn\n\t}\n\n\tconfigRoutes()\n\n\ts := &http.Server{\n\t\tAddr:           addr,\n\t\tMaxHeaderBytes: 1 << 30,\n\t}\n\n\tlog.Println(\"http.startHttpServer ok, listening\", addr)\n\tlog.Fatalln(s.ListenAndServe())\n}\n\nfunc RenderJson(w http.ResponseWriter, v interface{}) {\n\tbs, err := json.Marshal(v)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\tw.Write(bs)\n}\n\nfunc RenderDataJson(w http.ResponseWriter, data interface{}) {\n\tRenderJson(w, Dto{Msg: \"success\", Data: data})\n}\n\nfunc RenderMsgJson(w http.ResponseWriter, msg string) {\n\tRenderJson(w, map[string]string{\"msg\": msg})\n}\n\nfunc AutoRender(w http.ResponseWriter, data interface{}, err error) {\n\tif err != nil {\n\t\tRenderMsgJson(w, err.Error())\n\t\treturn\n\t}\n\tRenderDataJson(w, data)\n}\n"
  },
  {
    "path": "modules/nodata/http/proc_http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/collector\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/config\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/config/service\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/judge\"\n)\n\nfunc configProcHttpRoutes() {\n\t// counters\n\thttp.HandleFunc(\"/proc/counters\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, g.GetAllCounters())\n\t})\n\thttp.HandleFunc(\"/statistics/all\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, g.GetAllCounters())\n\t})\n\n\t// judge.status, /proc/status/$endpoint/$metric/$tags-pairs\n\thttp.HandleFunc(\"/proc/status/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/proc/status/\"):]\n\t\tRenderDataJson(w, judge.GetNodataStatus(urlParam))\n\t})\n\n\t// collector.last.item, /proc/collect/$endpoint/$metric/$tags-pairs\n\thttp.HandleFunc(\"/proc/collect/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/proc/collect/\"):]\n\t\titem, _ := collector.GetFirstItem(urlParam)\n\t\tRenderDataJson(w, item.String())\n\t})\n\n\t// config.mockcfg\n\thttp.HandleFunc(\"/proc/config\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, service.GetMockCfgFromDB())\n\t})\n\t// config.mockcfg /proc/config/$endpoint/$metric/$tags-pairs\n\thttp.HandleFunc(\"/proc/config/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/proc/config/\"):]\n\t\tcfg, _ := config.GetNdConfig(urlParam)\n\t\tRenderDataJson(w, cfg)\n\t})\n\n\t// config.hostgroup, /group/$grpname\n\thttp.HandleFunc(\"/proc/group/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/proc/group/\"):]\n\t\tRenderDataJson(w, service.GetHostsFromGroup(urlParam))\n\t})\n}\n"
  },
  {
    "path": "modules/nodata/judge/judge.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage judge\n\nimport (\n\t\"log\"\n)\n\nfunc Start() {\n\tStartJudgeCron()\n\tlog.Println(\"judge.Start ok\")\n}\n"
  },
  {
    "path": "modules/nodata/judge/judge_cron.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage judge\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\ttcron \"github.com/toolkits/cron\"\n\tttime \"github.com/toolkits/time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/collector\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/config\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/sender\"\n)\n\nvar (\n\tjudgeCron     = tcron.New()\n\tjudgeCronSpec = \"0 * * * * ?\"\n)\n\nfunc StartJudgeCron() {\n\tjudgeCron.AddFuncCC(judgeCronSpec, func() {\n\t\tstart := time.Now().Unix()\n\t\tjudge()\n\t\tend := time.Now().Unix()\n\t\tif g.Config().Debug {\n\t\t\tlog.Printf(\"judge cron, time %ds, start %s\\n\", end-start, ttime.FormatTs(start))\n\t\t}\n\n\t\t// statistics\n\t\tg.JudgeCronCnt.Incr()\n\t\tg.JudgeLastTs.SetCnt(end - start)\n\n\t\t// trigger sender\n\t\tsender.SendMockOnceAsync()\n\t}, 1)\n\tjudgeCron.Start()\n}\n\n// Do Judge\nfunc judge() {\n\tnow := time.Now().Unix()\n\tkeys := config.Keys()\n\tfor _, key := range keys {\n\t\tndcfg, found := config.GetNdConfig(key)\n\t\tif !found { //策略不存在,不处理\n\t\t\tcontinue\n\t\t}\n\t\tstep := ndcfg.Step\n\t\tmock := ndcfg.Mock\n\n\t\titem, found := collector.GetFirstItem(key)\n\t\tif !found { //没有数据,未开始采集,不处理\n\t\t\tcontinue\n\t\t}\n\n\t\tlastTs := now - getTimeout(step)\n\t\tif item.FStatus != \"OK\" || item.FTs < lastTs { //数据采集失败,不处理\n\t\t\tcontinue\n\t\t}\n\n\t\tif fCompare(mock, item.Value) == 0 { //采集到的数据为mock数据,则认为上报超时了\n\t\t\tif LastTs(key)+step <= now {\n\t\t\t\tTurnNodata(key, now)\n\t\t\t\tgenMock(genTs(now, step), key, ndcfg)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif item.Ts < lastTs { //数据过期, 则认为上报超时\n\t\t\tif LastTs(key)+step <= now {\n\t\t\t\tTurnNodata(key, now)\n\t\t\t\tgenMock(genTs(now, step), key, ndcfg)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tTurnOk(key, now)\n\t}\n}\n\nfunc genMock(ts int64, key string, ndcfg *cmodel.NodataConfig) {\n\tsender.AddMock(key, ndcfg.Endpoint, ndcfg.Metric, cutils.SortedTags(ndcfg.Tags), ts, ndcfg.Type, ndcfg.Step, ndcfg.Mock)\n}\n\n//mock的数据,要前移1+个周期、防止覆盖正常值\nfunc genTs(nowTs int64, step int64) int64 {\n\tif step < 1 {\n\t\tstep = 60\n\t}\n\n\treturn nowTs - nowTs%step - 2*step\n}\n\nfunc getTimeout(step int64) int64 {\n\tif step < 60 {\n\t\treturn 180 //60*3\n\t}\n\n\treturn step * 3\n}\n\nconst minfloat64 = 0.000001\n\nfunc fCompare(left, right float64) int {\n\tsub := left - right\n\tif sub > -minfloat64 && sub < minfloat64 {\n\t\treturn 0\n\t}\n\tif sub >= minfloat64 {\n\t\treturn 1\n\t}\n\treturn -1\n}\n"
  },
  {
    "path": "modules/nodata/judge/status.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage judge\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/toolkits/container/nmap\"\n\tttime \"github.com/toolkits/time\"\n)\n\n// Nodata Status Cache\nvar (\n\tstatusLock = sync.RWMutex{}\n\tStatusMap  = nmap.NewSafeMap()\n)\n\nfunc LastTs(key string) int64 {\n\tstatusLock.RLock()\n\n\tvar ts int64 = 0\n\tv, found := StatusMap.Get(key)\n\tif !found {\n\t\tstatusLock.RUnlock()\n\t\treturn ts\n\t}\n\n\tts = v.(*NodataStatus).Ts\n\n\tstatusLock.RUnlock()\n\treturn ts\n}\n\nfunc TurnOk(key string, ts int64) {\n\tstatusLock.Lock()\n\n\tv, found := StatusMap.Get(key)\n\tif !found {\n\t\t// create new status\n\t\tns := NewNodataStatus(key, \"OK\", 0, ts)\n\t\tStatusMap.Put(key, ns)\n\t\tstatusLock.Unlock()\n\t\treturn\n\t}\n\n\t// update status\n\tns := v.(*NodataStatus)\n\tns.Status = \"OK\"\n\tns.Cnt = 0\n\tns.Ts = ts\n\n\tstatusLock.Unlock()\n\treturn\n}\n\nfunc TurnNodata(key string, ts int64) {\n\tstatusLock.Lock()\n\n\tv, found := StatusMap.Get(key)\n\tif !found {\n\t\t// create new status\n\t\tns := NewNodataStatus(key, \"NODATA\", 1, ts)\n\t\tStatusMap.Put(key, ns)\n\t\tstatusLock.Unlock()\n\t\treturn\n\t}\n\n\t// update status\n\tns := v.(*NodataStatus)\n\tns.Status = \"NODATA\"\n\tns.Cnt += 1\n\tns.Ts = ts\n\n\tstatusLock.Unlock()\n\treturn\n}\n\nfunc GetNodataStatus(key string) *NodataStatus {\n\tstatusLock.RLock()\n\tdefer statusLock.RUnlock()\n\n\tv, found := StatusMap.Get(key)\n\tif !found {\n\t\treturn &NodataStatus{}\n\t}\n\treturn v.(*NodataStatus)\n}\n\nfunc GetAllNodataStatus() []*NodataStatus {\n\tstatusLock.RLock()\n\tdefer statusLock.RUnlock()\n\n\tret := make([]*NodataStatus, 0)\n\tkeys := StatusMap.Keys()\n\tfor _, key := range keys {\n\t\tif v, found := StatusMap.Get(key); found {\n\t\t\tret = append(ret, v.(*NodataStatus))\n\t\t}\n\t}\n\n\treturn ret\n}\n\n// Nodata Status Struct\ntype NodataStatus struct {\n\tKey    string\n\tStatus string // OK|NODATA\n\tCnt    int\n\tTs     int64\n}\n\nfunc NewNodataStatus(key string, status string, cnt int, ts int64) *NodataStatus {\n\treturn &NodataStatus{key, status, cnt, ts}\n}\n\nfunc (this *NodataStatus) String() string {\n\treturn fmt.Sprintf(\"NodataStatus key=%s status=%s cnt=%d ts=%d date=%s\",\n\t\tthis.Key, this.Status, this.Cnt, this.Ts, ttime.FormatTs(this.Ts))\n}\n"
  },
  {
    "path": "modules/nodata/main.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/collector\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/config\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/http\"\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/judge\"\n)\n\nfunc main() {\n\tg.BinaryName = BinaryName\n\tg.Version = Version\n\tg.GitCommit = GitCommit\n\n\tcfg := flag.String(\"c\", \"cfg.json\", \"configuration file\")\n\tversion := flag.Bool(\"v\", false, \"show version\")\n\tversionGit := flag.Bool(\"vg\", false, \"show version\")\n\tflag.Parse()\n\n\tif *version {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\tif *versionGit {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\n\t// global config\n\tg.ParseConfig(*cfg)\n\t// proc\n\tg.StartProc()\n\n\t// config\n\tconfig.Start()\n\t// collector\n\tcollector.Start()\n\t// judge\n\tjudge.Start()\n\n\t// http\n\thttp.Start()\n\n\tselect {}\n}\n"
  },
  {
    "path": "modules/nodata/scripts/debug",
    "content": "#!/bin/bash\n## test home\ntestdir=$(cd $(dirname $0)/; pwd)\n## word home\nworkdir=$(dirname $testdir)\ncd $workdir\n\ncontrol=./control\n\ncfg=./cfg.json\nhttpport=`cat cfg.json | grep -A3 \"\\\"http\\\":\" | grep \"\\\"listen\\\"\" | cut -d\\\" -f4 | cut -d: -f2`\nhttpprex=\"127.0.0.1:$httpport\"\n\n## proc\nfunction proc(){\n    args=$@\n    for i in $@; do\n        url=\"$url/$i\"\n    done\n    curl -s \"$httpprex$url\" | python -m json.tool\n}\n\n## config\nfunction config(){\n    args=$@\n    for i in $@; do\n        url=\"$url/$i\"\n    done\n    curl -s \"$httpprex$url\" | python -m json.tool\n}\n\n## api\nfunction api(){\n    args=$@\n    for i in $@; do\n        url=\"$url/$i\"\n    done\n    curl -s \"$httpprex$url\" | python -m json.tool\n}\n\n## debug\nfunction debug(){\n    args=$@\n    for i in $@; do\n        url=\"$url/$i\"\n    done\n    curl -s \"$httpprex$url\" | python -m json.tool\n}\n\n## control\nfunction control(){\n    $control $@\n}\n\naction=$1\ncase $action in\n    \"proc\")\n        proc $@\n        ;;\n    \"config\")\n        config $@\n        ;;\n    \"api\")\n        api $@\n        ;;\n    \"debug\")\n        debug $@\n        ;;\n    \"\")\n        proc \"proc\" \"counters\"\n        ;;\n    *)\n        control $@\n        ;;\nesac\n\n"
  },
  {
    "path": "modules/nodata/scripts/nodata-db-schema.sql",
    "content": "#CREATE DATABASE `falcon_portal`;\nUSE `falcon_portal`;\nSET NAMES 'utf8';\n\n/**\n * nodata mock config\n */\nDROP TABLE IF EXISTS `mockcfg`;\nCREATE TABLE `mockcfg` (\n  `id`       BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,\n  `name`     VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'name of mockcfg, used for uuid',\n  `obj`      VARCHAR(10240) NOT NULL DEFAULT '' COMMENT 'desc of object',\n  `obj_type` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'type of object, host or group or other',\n  `metric`   VARCHAR(128) NOT NULL DEFAULT '',\n  `tags`     VARCHAR(1024) NOT NULL DEFAULT '',\n  `dstype`   VARCHAR(32)  NOT NULL DEFAULT 'GAUGE',\n  `step`     INT(11) UNSIGNED  NOT NULL DEFAULT 60,\n  `mock`     DOUBLE  NOT NULL DEFAULT 0  COMMENT 'mocked value when nodata occurs',\n  `creator`  VARCHAR(64)  NOT NULL DEFAULT '',\n  `t_create` DATETIME NOT NULL COMMENT 'create time',\n  `t_modify` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'last modify time',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `uniq_name` (`name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;\n\n"
  },
  {
    "path": "modules/nodata/sender/sender.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\ttsema \"github.com/toolkits/concurrent/semaphore\"\n\t\"github.com/toolkits/container/nmap\"\n\tthttpclient \"github.com/toolkits/http/httpclient\"\n\tttime \"github.com/toolkits/time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/nodata/g\"\n)\n\nvar (\n\tMockMap = nmap.NewSafeMap()\n\tsema    = tsema.NewSemaphore(1)\n)\n\nfunc AddMock(key string, endpoint string, metric string, tags string, ts int64, dstype string, step int64, value interface{}) {\n\titem := &cmodel.JsonMetaData{metric, endpoint, ts, step, value, dstype, tags}\n\tMockMap.Put(key, item)\n}\n\nfunc SendMockOnceAsync() {\n\tgo SendMockOnce()\n}\n\nfunc SendMockOnce() int {\n\tif !sema.TryAcquire() {\n\t\treturn -1\n\t}\n\tdefer sema.Release()\n\n\t// not enabled\n\tif !g.Config().Sender.Enabled {\n\t\treturn 0\n\t}\n\n\tstart := time.Now().Unix()\n\tcnt, _ := sendMock()\n\tend := time.Now().Unix()\n\tif g.Config().Debug {\n\t\tlog.Printf(\"sender cron, cnt %d, time %ds, start %s\", cnt, end-start, ttime.FormatTs(start))\n\t}\n\n\t// statistics\n\tg.SenderCronCnt.Incr()\n\tg.SenderLastTs.SetCnt(end - start)\n\tg.SenderCnt.IncrBy(int64(cnt))\n\n\treturn cnt\n}\n\nfunc sendMock() (cnt int, errt error) {\n\n\tcfg := g.Config().Sender\n\tbatch := int(cfg.Batch)\n\tconnTimeout := cfg.ConnectTimeout\n\trequTimeout := cfg.RequestTimeout\n\n\t// send mock to transfer\n\tmocks := MockMap.Slice()\n\tMockMap.Clear()\n\tmockSize := len(mocks)\n\ti := 0\n\tfor i < mockSize {\n\t\tleftLen := mockSize - i\n\t\tsendSize := batch\n\t\tif leftLen < sendSize {\n\t\t\tsendSize = leftLen\n\t\t}\n\t\tfetchMocks := mocks[i : i+sendSize]\n\t\ti += sendSize\n\n\t\titems := make([]*cmodel.JsonMetaData, 0)\n\t\tfor _, val := range fetchMocks {\n\t\t\tif val == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\titems = append(items, val.(*cmodel.JsonMetaData))\n\t\t}\n\t\tcntonce, err := sendItemsToTransfer(items, len(items), \"nodata.mock\",\n\t\t\ttime.Millisecond*time.Duration(connTimeout),\n\t\t\ttime.Millisecond*time.Duration(requTimeout))\n\t\tif err == nil {\n\t\t\tif g.Config().Debug {\n\t\t\t\tlog.Println(\"send items:\", items)\n\t\t\t}\n\t\t\tcnt += cntonce\n\t\t}\n\t}\n\n\treturn cnt, nil\n}\n\n//\nfunc sendItemsToTransfer(items []*cmodel.JsonMetaData, size int, httpcliname string,\n\tconnT, reqT time.Duration) (cnt int, errt error) {\n\tif size < 1 {\n\t\treturn\n\t}\n\n\tcfg := g.Config()\n\ttransUlr := fmt.Sprintf(\"http://%s/api/push\", cfg.Sender.TransferAddr)\n\thcli := thttpclient.GetHttpClient(httpcliname, connT, reqT)\n\n\t// form request args\n\titemsBody, err := json.Marshal(items)\n\tif err != nil {\n\t\tlog.Println(transUlr+\", format body error,\", err)\n\t\terrt = err\n\t\treturn\n\t}\n\n\t// fetch items\n\treq, err := http.NewRequest(\"POST\", transUlr, bytes.NewBuffer(itemsBody))\n\treq.Header.Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\treq.Header.Set(\"Connection\", \"close\")\n\tpostResp, err := hcli.Do(req)\n\tif err != nil {\n\t\tlog.Println(transUlr+\", post to dest error,\", err)\n\t\terrt = err\n\t\treturn\n\t}\n\tdefer postResp.Body.Close()\n\n\tif postResp.StatusCode/100 != 2 {\n\t\tlog.Println(transUlr+\", post to dest, bad response,\", postResp.Body)\n\t\terrt = fmt.Errorf(\"request failed, %s\", postResp.Body)\n\t\treturn\n\t}\n\n\treturn size, nil\n}\n"
  },
  {
    "path": "modules/nodata/version.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// build !release\npackage main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  },
  {
    "path": "modules/transfer/.gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n*.swp\n*.swo\n*.log\n.idea\n.DS_Store\n/var\n/falcon-transfer*\n/cfg.json\n/test/build\n/test/*.go\n\ngitversion\n"
  },
  {
    "path": "modules/transfer/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "modules/transfer/NOTICE",
    "content": "Open-Falcon\n\nCopyright (c) 2014-2015 Xiaomi, Inc. All Rights Reserved.\n\nThis product is licensed to you under the Apache License, Version 2.0 (the \"License\").\nYou may not use this product except in compliance with the License.\n\nThis product may include a number of subcomponents with separate copyright notices\nand license terms. Your use of these subcomponents is subject to the terms and\nconditions of the subcomponent's license, as noted in the LICENSE file.\n"
  },
  {
    "path": "modules/transfer/README.md",
    "content": "## Introduction\n\n数据收集，是监控系统一个最基本的功能，在Open-Falcon中，Agent采集到的数据，会先发送给Transfer组件。Transfer在接收到客户端发送的数据，做一些数据规整，检查之后，转发到多个后端系统去处理。在转发到每个后端业务系统的时候，Transfer会根据一致性哈希算法，进行数据分片，来达到后端业务系统的水平扩展。Transfer自身是无状态的，挂掉一台或者多台不会有任何影响。\n\nTransfer支持的业务后端，有三种，Judge、Graph、OpenTSDB。Judge是我们开发的高性能告警判定组件，Graph是我们开发的高性能数据存储、归档、查询组件，OpenTSDB是开源的时间序列数据存储服务。每个业务后端，都可以通过Transfer的配置文件来开启。\n\nTransfer的数据来源，一般有四种：\n\n1.Falcon-agent主动采集的基础监控数据。\n2.Falcon-agent执行用户自定义的插件返回的数据。\n3.client-library：线上的业务系统，都嵌入使用了统一的基础库，对于业务系统中每个业务接口，都会主动计算其qps、latency等指标，并上报。\n4.用户产生的一些自定义的指标，由用户自行上报。\n\n这四种数据，都会先发送给本机的Proxy-gateway，再由Proxy-gateway转发给Transfer\n\n一个推送数据给Proxy-gateway的例子：\n\n```python\n#!-*- coding:utf8 -*-\n    \nimport requests\nimport time\nimport json\n\nts = int(time.time())\npayload = [\n    {\n        \"endpoint\": \"test-endpoint\",\n        \"metric\": \"test-metric\",\n        \"timestamp\": ts,\n        \"step\": 60,\n        \"value\": 1,\n        \"counterType\": \"GAUGE\",\n        \"tags\": \"location=beijing,service=falcon\",\n    },\n]\nr=requests.post(\"http://127.0.0.1:1988/v1/push\",data=json.dumps(payload))\nprint r.text\n```\n\n## Installation\n\n```bash\n# set $GOPATH and $GOROOT\n\nmkdir -p $GOPATH/src/github.com/open-falcon\ncd $GOPATH/src/github.com/open-falcon\ngit clone https://github.com/open-falcon/transfer.git\n\ncd transfer\ngo get ./...\n./control build\n\n./control start\n```\n## Usage\nsend items via transfer's http-api\n```bash\n#!/bin/bash\ne=\"test.endpoint.1\" \nm=\"test.metric.1\"\nt=\"t0=tag0,t1=tag1,t2=tag2\"\nts=`date +%s`\ncurl -s -X POST -d \"[{\\\"metric\\\":\\\"$m\\\", \\\"endpoint\\\":\\\"$e\\\", \\\"timestamp\\\":$ts,\\\"step\\\":60, \\\"value\\\":9, \\\"counterType\\\":\\\"GAUGE\\\",\\\"tags\\\":\\\"$t\\\"}]\" \"127.0.0.1:6060/api/push\" | python -m json.tool\n```\n\nu want sending items via python jsonrpc client? turn to one python example: ```./test/rcpclient.py```\n\nu want sending items via java jsonrpc client? turn to one java example: [jsonrpc4go](https://github.com/niean/jsonrpc4go)\n\n## Configuration\n\n    debug: true/false, 如果为true，日志中会打印debug信息\n\n    minStep: 30, 允许上报的数据最小间隔，默认为30秒\n\n    http\n        - enable: true/false, 表示是否开启该http端口，该端口为控制端口，主要用来对transfer发送控制命令、统计命令、debug命令等\n        - listen: 表示监听的http端口\n\n    rpc\n        - enable: true/false, 表示是否开启该jsonrpc数据接收端口, Agent发送数据使用的就是该端口\n        - listen: 表示监听的http端口\n\n    socket #即将被废弃,请避免使用\n        - enable: true/false, 表示是否开启该telnet方式的数据接收端口，这是为了方便用户一行行的发送数据给transfer\n        - listen: 表示监听的http端口\n\n    judge\n        - enable: true/false, 表示是否开启向judge发送数据\n        - batch: 数据转发的批量大小，可以加快发送速度，建议保持默认值\n        - connTimeout: 单位是毫秒，与后端建立连接的超时时间，可以根据网络质量微调，建议保持默认\n        - callTimeout: 单位是毫秒，发送数据给后端的超时时间，可以根据网络质量微调，建议保持默认\n        - pingMethod: 后端提供的ping接口，用来探测连接是否可用，必须保持默认\n        - maxConns: 连接池相关配置，最大连接数，建议保持默认\n        - maxIdle: 连接池相关配置，最大空闲连接数，建议保持默认\n        - replicas: 这是一致性hash算法需要的节点副本数量，建议不要变更，保持默认即可\n        - cluster: key-value形式的字典，表示后端的judge列表，其中key代表后端judge名字，value代表的是具体的ip:port\n\n    graph\n        - enable: true/false, 表示是否开启向graph发送数据\n        - batch: 数据转发的批量大小，可以加快发送速度，建议保持默认值\n        - connTimeout: 单位是毫秒，与后端建立连接的超时时间，可以根据网络质量微调，建议保持默认\n        - callTimeout: 单位是毫秒，发送数据给后端的超时时间，可以根据网络质量微调，建议保持默认\n        - pingMethod: 后端提供的ping接口，用来探测连接是否可用，必须保持默认\n        - maxConns: 连接池相关配置，最大连接数，建议保持默认\n        - maxIdle: 连接池相关配置，最大空闲连接数，建议保持默认\n        - replicas: 这是一致性hash算法需要的节点副本数量，建议不要变更，保持默认即可\n        - cluster: key-value形式的字典，表示后端的graph列表，其中key代表后端graph名字，value代表的是具体的ip:port(多个地址用逗号隔开, transfer会将同一份数据发送至各个地址，利用这个特性可以实现数据的多重备份)\n\n    tsdb\n        - enabled: true/false, 表示是否开启向open tsdb发送数据\n        - batch: 数据转发的批量大小，可以加快发送速度\n        - connTimeout: 单位是毫秒，与后端建立连接的超时时间，可以根据网络质量微调，建议保持默认\n        - callTimeout: 单位是毫秒，发送数据给后端的超时时间，可以根据网络质量微调，建议保持默认\n        - maxConns: 连接池相关配置，最大连接数，建议保持默认\n        - maxIdle: 连接池相关配置，最大空闲连接数，建议保持默认\n        - retry: 连接后端的重试次数和发送数据的重试次数\n        - address: tsdb地址或者tsdb集群vip地址, 通过tcp连接tsdb. \n\n    p8s_relay\n        - enable: true/false, 表示是否开启向falcon2p8s exporter发送数据\n        - batch: 数据转发的批量大小，可以加快发送速度，建议保持默认值\n        - connTimeout: 单位是毫秒，与后端建立连接的超时时间，可以根据网络质量微调，建议保持默认\n        - callTimeout: 单位是毫秒，发送数据给后端的超时时间，可以根据网络质量微调，建议保持默认\n        - maxConns: 连接池相关配置，最大连接数，建议保持默认\n        - maxIdle: 连接池相关配置，最大空闲连接数，建议保持默认\n        - replicas: 这是一致性hash算法需要的节点副本数量，建议不要变更，保持默认即可\n        - notSyncMetrics: 不发送到falcon2p8s exporter的metric列表，前缀匹配\n        - cluster: key-value形式的字典，表示后端的falcon2p8s exporter列表，其中key代表后端exporter名字，value代表的是具体的ip:port\n"
  },
  {
    "path": "modules/transfer/cfg.example.json",
    "content": "{\n    \"debug\": true,\n    \"minStep\": 30,\n    \"http\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:6060\"\n    },\n    \"rpc\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:8433\"\n    },\n    \"socket\": {\n        \"enabled\": true,\n        \"listen\": \"0.0.0.0:4444\",\n        \"timeout\": 3600\n    },\n    \"judge\": {\n        \"enabled\": true,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"cluster\": {\n            \"judge-00\" : \"127.0.0.1:6080\"\n        }\n    },\n    \"graph\": {\n        \"enabled\": true,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"cluster\": {\n            \"graph-00\" : \"127.0.0.1:6070\"\n        }\n    },\n    \"tsdb\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"retry\": 3,\n        \"address\": \"127.0.0.1:8088\"\n    },\n    \"transfer\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"retry\": 3,\n        \"cluster\": {\n            \"t1\": \"127.0.0.1:8433\"\n        }\n    },\n    \"influxdb\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"retry\": 3,\n        \"maxConns\": 32,\n        \"username\": \"admin\",\n        \"password\": \"123456\",\n        \"precision\": \"s\",\n        \"db\": \"foo\",\n        \"address\": \"http://127.0.0.1:8086\",\n        \"timeout\": 5000\n    },\n    \"p8s_relay\": {\n        \"enabled\": false,\n        \"batch\": 200,\n        \"connTimeout\": 1000,\n        \"callTimeout\": 5000,\n        \"maxConns\": 32,\n        \"maxIdle\": 32,\n        \"replicas\": 500,\n        \"notSyncMetrics\": [\n            \"gpu.\",\n            \"snmp.\"\n        ],\n        \"cluster\": {\n            \"p8s-relay-00\" : \"192.168.1.1:8080\", \n            \"p8s-relay-01\" : \"192.168.1.2:8080\"\n        }\n    }\n}\n"
  },
  {
    "path": "modules/transfer/control",
    "content": "#!/bin/bash\n\nWORKSPACE=$(cd $(dirname $0)/; pwd)\ncd $WORKSPACE\n\nmkdir -p var\n\nmodule=transfer\napp=falcon-$module\nconf=cfg.json\npidfile=var/app.pid\nlogfile=var/app.log\n\nfunction check_pid() {\n    if [ -f $pidfile ];then\n        pid=`cat $pidfile`\n        if [ -n $pid ]; then\n            running=`ps -p $pid|grep -v \"PID TTY\" |wc -l`\n            return $running\n        fi\n    fi\n    return 0\n}\n\nfunction start() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running already, pid=\"\n        cat $pidfile\n        return 1\n    fi\n\n    nohup ./$app -c $conf &> $logfile &\n    echo $! > $pidfile\n    echo \"$app started..., pid=$!\"\n}\n\nfunction stop() {\n    pid=`cat $pidfile`\n    kill -9 $pid\n    echo \"$app stopped...\"\n}\n\nfunction restart() {\n    stop\n    sleep 1\n    start\n}\n\nfunction status() {\n    check_pid\n    running=$?\n    if [ $running -gt 0 ];then\n        echo -n \"$app now is running, pid=\"\n        cat $pidfile\n    else\n        echo \"$app is stopped\"\n    fi\n}\n\nfunction tailf() {\n    tail -f $logfile\n}\n\nfunction build() {\n    commit=$(git log -1 --pretty=%h)\n    cat <<EOF > ./g/git.go\npackage g\nconst (\n    COMMIT = \"$commit\"\n)\nEOF\n    go build -o $app main.go\n    show_version\n}\n\nfunction show_version() {\n    ./$app -vg\n}\n\nfunction pack() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-$version.tar.gz control $app cfg.example.json gitversion ./test/debug\n}\n\nfunction packbin() {\n    build\n    git log -1 --pretty=%h > gitversion\n    version=`./$app -v`\n    tar zcvf $app-bin-$version.tar.gz $app gitversion\n}\n\n\nfunction help() {\n    echo \"$0 build|pack|packbin|start|stop|restart|status|tail\"\n}\n\nif [ \"$1\" == \"\" ]; then\n    help\nelif [ \"$1\" == \"stop\" ];then\n    stop\nelif [ \"$1\" == \"start\" ];then\n    start\nelif [ \"$1\" == \"restart\" ];then\n    restart\nelif [ \"$1\" == \"status\" ];then\n    status\nelif [ \"$1\" == \"tail\" ];then\n    tailf\nelif [ \"$1\" == \"build\" ];then\n    build\nelif [ \"$1\" == \"packbin\" ];then\n    packbin\nelif [ \"$1\" == \"pack\" ];then\n    pack\nelse\n    help\nfi\n"
  },
  {
    "path": "modules/transfer/g/cfg.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/toolkits/file\"\n)\n\ntype HttpConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype RpcConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n}\n\ntype SocketConfig struct {\n\tEnabled bool   `json:\"enabled\"`\n\tListen  string `json:\"listen\"`\n\tTimeout int    `json:\"timeout\"`\n}\n\ntype JudgeConfig struct {\n\tEnabled     bool                    `json:\"enabled\"`\n\tBatch       int                     `json:\"batch\"`\n\tConnTimeout int                     `json:\"connTimeout\"`\n\tCallTimeout int                     `json:\"callTimeout\"`\n\tMaxConns    int                     `json:\"maxConns\"`\n\tMaxIdle     int                     `json:\"maxIdle\"`\n\tReplicas    int                     `json:\"replicas\"`\n\tCluster     map[string]string       `json:\"cluster\"`\n\tClusterList map[string]*ClusterNode `json:\"clusterList\"`\n}\n\ntype GraphConfig struct {\n\tEnabled     bool                    `json:\"enabled\"`\n\tBatch       int                     `json:\"batch\"`\n\tConnTimeout int                     `json:\"connTimeout\"`\n\tCallTimeout int                     `json:\"callTimeout\"`\n\tMaxConns    int                     `json:\"maxConns\"`\n\tMaxIdle     int                     `json:\"maxIdle\"`\n\tReplicas    int                     `json:\"replicas\"`\n\tCluster     map[string]string       `json:\"cluster\"`\n\tClusterList map[string]*ClusterNode `json:\"clusterList\"`\n}\n\ntype TsdbConfig struct {\n\tEnabled     bool   `json:\"enabled\"`\n\tBatch       int    `json:\"batch\"`\n\tConnTimeout int    `json:\"connTimeout\"`\n\tCallTimeout int    `json:\"callTimeout\"`\n\tMaxConns    int    `json:\"maxConns\"`\n\tMaxIdle     int    `json:\"maxIdle\"`\n\tMaxRetry    int    `json:\"retry\"`\n\tAddress     string `json:\"address\"`\n}\n\ntype TransferConfig struct {\n\tEnabled     bool              `json:\"enabled\"`\n\tBatch       int               `json:\"batch\"`\n\tConnTimeout int               `json:\"connTimeout\"`\n\tCallTimeout int               `json:\"callTimeout\"`\n\tMaxConns    int               `json:\"maxConns\"`\n\tMaxIdle     int               `json:\"maxIdle\"`\n\tMaxRetry    int               `json:\"retry\"`\n\tCluster     map[string]string `json:\"cluster\"`\n}\n\ntype InfluxdbConfig struct {\n\tEnabled   bool   `json:\"enabled\"`\n\tBatch     int    `json:\"batch\"`\n\tMaxRetry  int    `json:\"retry\"`\n\tMaxConns  int    `json:\"maxConns\"`\n\tTimeout   int    `json:\"timeout\"`\n\tAddress   string `json:\"address\"`\n\tDatabase  string `json:\"db\"`\n\tUsername  string `json:\"username\"`\n\tPassword  string `json:\"password\"`\n\tPrecision string `json:\"precision\"`\n}\n\ntype P8sRelayConfig struct {\n\tEnabled        bool                    `json:\"enabled\"`\n\tBatch          int                     `json:\"batch\"`\n\tConnTimeout    int                     `json:\"connTimeout\"`\n\tCallTimeout    int                     `json:\"callTimeout\"`\n\tMaxConns       int                     `json:\"maxConns\"`\n\tMaxIdle        int                     `json:\"maxIdle\"`\n\tReplicas       int                     `json:\"replicas\"`\n\tNotSyncMetrics []string                `json:\"notSyncMetrics\"`\n\tCluster        map[string]string       `json:\"cluster\"`\n\tClusterList    map[string]*ClusterNode `json:\"clusterList\"`\n}\n\ntype GlobalConfig struct {\n\tDebug    bool            `json:\"debug\"`\n\tMinStep  int             `json:\"minStep\"` //最小周期,单位sec\n\tHttp     *HttpConfig     `json:\"http\"`\n\tRpc      *RpcConfig      `json:\"rpc\"`\n\tSocket   *SocketConfig   `json:\"socket\"`\n\tJudge    *JudgeConfig    `json:\"judge\"`\n\tGraph    *GraphConfig    `json:\"graph\"`\n\tTsdb     *TsdbConfig     `json:\"tsdb\"`\n\tTransfer *TransferConfig `json:\"transfer\"`\n\tInfluxdb *InfluxdbConfig `json:\"influxdb\"`\n\tP8sRelay *P8sRelayConfig `json:\"p8s_relay\"`\n}\n\nvar (\n\tConfigFile string\n\tconfig     *GlobalConfig\n\tconfigLock = new(sync.RWMutex)\n)\n\nfunc Config() *GlobalConfig {\n\tconfigLock.RLock()\n\tdefer configLock.RUnlock()\n\treturn config\n}\n\nfunc ParseConfig(cfg string) {\n\tif cfg == \"\" {\n\t\tlog.Fatalln(\"use -c to specify configuration file\")\n\t}\n\n\tif !file.IsExist(cfg) {\n\t\tlog.Fatalln(\"config file:\", cfg, \"is not existent. maybe you need `mv cfg.example.json cfg.json`\")\n\t}\n\n\tConfigFile = cfg\n\n\tconfigContent, err := file.ToTrimString(cfg)\n\tif err != nil {\n\t\tlog.Fatalln(\"read config file:\", cfg, \"fail:\", err)\n\t}\n\n\tvar c GlobalConfig\n\terr = json.Unmarshal([]byte(configContent), &c)\n\tif err != nil {\n\t\tlog.Fatalln(\"parse config file:\", cfg, \"fail:\", err)\n\t}\n\n\t// split cluster config\n\tc.Judge.ClusterList = formatClusterItems(c.Judge.Cluster)\n\tc.Graph.ClusterList = formatClusterItems(c.Graph.Cluster)\n\tc.P8sRelay.ClusterList = formatClusterItems(c.P8sRelay.Cluster)\n\n\tconfigLock.Lock()\n\tdefer configLock.Unlock()\n\tconfig = &c\n\n\tlog.Println(\"g.ParseConfig ok, file \", cfg)\n}\n\n// CLUSTER NODE\ntype ClusterNode struct {\n\tAddrs []string `json:\"addrs\"`\n}\n\nfunc NewClusterNode(addrs []string) *ClusterNode {\n\treturn &ClusterNode{addrs}\n}\n\n// map[\"node\"]=\"host1,host2\" --> map[\"node\"]=[\"host1\", \"host2\"]\nfunc formatClusterItems(cluster map[string]string) map[string]*ClusterNode {\n\tret := make(map[string]*ClusterNode)\n\tfor node, clusterStr := range cluster {\n\t\titems := strings.Split(clusterStr, \",\")\n\t\tnitems := make([]string, 0)\n\t\tfor _, item := range items {\n\t\t\tnitems = append(nitems, strings.TrimSpace(item))\n\t\t}\n\t\tret[node] = NewClusterNode(nitems)\n\t}\n\n\treturn ret\n}\n"
  },
  {
    "path": "modules/transfer/g/g.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nimport (\n\t\"log\"\n\t\"runtime\"\n)\n\n// changelog:\n// 0.0.1: init project\n// 0.0.4: bugfix: set replicas before add node\n// 0.0.8: change receiver, mv proc cron to proc pkg, add readme, add gitversion, add config reload, add trace tools\n// 0.0.9: fix bugs of conn pool(use transfer's private conn pool, named & minimum)\n// 0.0.10: use more efficient proc & sema, rm conn_pool status log\n// 0.0.11: fix bug: all graphs' traffic delined when one graph broken down, modify retry interval\n// 0.0.14: support sending multi copies to graph node, align ts for judge, add filter\n// 0.0.15: support tsdb\n// 0.0.16: support config of min step\n// 0.0.17: remove migrating, which is implemented in graph\n\nvar (\n\tBinaryName string\n\tVersion    string\n\tGitCommit  string\n)\n\nfunc VersionMsg() string {\n\treturn Version + \"@\" + GitCommit\n}\n\nconst (\n\tGAUGE        = \"GAUGE\"\n\tCOUNTER      = \"COUNTER\"\n\tDERIVE       = \"DERIVE\"\n\tDEFAULT_STEP = 60\n)\n\nfunc init() {\n\truntime.GOMAXPROCS(runtime.NumCPU())\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)\n}\n"
  },
  {
    "path": "modules/transfer/g/git.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage g\n\nconst (\n\tCOMMIT = \"e249d8a\"\n)\n"
  },
  {
    "path": "modules/transfer/http/api.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"encoding/json\"\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tprpc \"github.com/open-falcon/falcon-plus/modules/transfer/receiver/rpc\"\n\t\"net/http\"\n)\n\nfunc api_push_datapoints(rw http.ResponseWriter, req *http.Request) {\n\tif req.ContentLength == 0 {\n\t\thttp.Error(rw, \"blank body\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tdecoder := json.NewDecoder(req.Body)\n\tvar metrics []*cmodel.MetricValue\n\terr := decoder.Decode(&metrics)\n\tif err != nil {\n\t\thttp.Error(rw, \"decode error\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\treply := &cmodel.TransferResponse{}\n\tprpc.RecvMetricValues(metrics, reply, \"http\")\n\n\tRenderDataJson(rw, reply)\n}\n\nfunc configApiRoutes() {\n\thttp.HandleFunc(\"/api/push\", api_push_datapoints)\n}\n"
  },
  {
    "path": "modules/transfer/http/common.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"github.com/toolkits/file\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc configCommonRoutes() {\n\thttp.HandleFunc(\"/health\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"ok\\n\"))\n\t})\n\n\thttp.HandleFunc(\"/version\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(fmt.Sprintf(\"%s\\n\", g.VersionMsg())))\n\t})\n\n\thttp.HandleFunc(\"/workdir\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(fmt.Sprintf(\"%s\\n\", file.SelfDir())))\n\t})\n\n\thttp.HandleFunc(\"/config\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, g.Config())\n\t})\n\n\thttp.HandleFunc(\"/config/reload\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif strings.HasPrefix(r.RemoteAddr, \"127.0.0.1\") {\n\t\t\tg.ParseConfig(g.ConfigFile)\n\t\t\tRenderDataJson(w, \"ok\")\n\t\t} else {\n\t\t\tRenderDataJson(w, \"no privilege\")\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "modules/transfer/http/debug_http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/sender\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc configDebugHttpRoutes() {\n\t// conn pools\n\thttp.HandleFunc(\"/debug/connpool/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/debug/connpool/\"):]\n\t\targs := strings.Split(urlParam, \"/\")\n\n\t\targsLen := len(args)\n\t\tif argsLen < 1 {\n\t\t\tw.Write([]byte(fmt.Sprintf(\"bad args\\n\")))\n\t\t\treturn\n\t\t}\n\n\t\tvar result string\n\t\treceiver := args[0]\n\t\tswitch receiver {\n\t\tcase \"judge\":\n\t\t\tresult = strings.Join(sender.JudgeConnPools.Proc(), \"\\n\")\n\t\tcase \"graph\":\n\t\t\tresult = strings.Join(sender.GraphConnPools.Proc(), \"\\n\")\n\t\tdefault:\n\t\t\tresult = fmt.Sprintf(\"bad args, module not exist\\n\")\n\t\t}\n\t\tw.Write([]byte(result))\n\t})\n}\n"
  },
  {
    "path": "modules/transfer/http/http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n)\n\ntype Dto struct {\n\tMsg  string      `json:\"msg\"`\n\tData interface{} `json:\"data\"`\n}\n\nfunc Start() {\n\tgo startHttpServer()\n}\n\nfunc startHttpServer() {\n\tif !g.Config().Http.Enabled {\n\t\treturn\n\t}\n\n\taddr := g.Config().Http.Listen\n\tif addr == \"\" {\n\t\treturn\n\t}\n\n\tconfigCommonRoutes()\n\tconfigProcHttpRoutes()\n\tconfigDebugHttpRoutes()\n\n\tconfigApiRoutes()\n\n\ts := &http.Server{\n\t\tAddr:           addr,\n\t\tMaxHeaderBytes: 1 << 30,\n\t}\n\n\tlog.Println(\"http.startHttpServer ok, listening\", addr)\n\tlog.Fatalln(s.ListenAndServe())\n}\n\nfunc RenderJson(w http.ResponseWriter, v interface{}) {\n\tbs, err := json.Marshal(v)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\tw.Write(bs)\n}\n\nfunc RenderDataJson(w http.ResponseWriter, data interface{}) {\n\tRenderJson(w, Dto{Msg: \"success\", Data: data})\n}\n\nfunc RenderMsgJson(w http.ResponseWriter, msg string) {\n\tRenderJson(w, map[string]string{\"msg\": msg})\n}\n\nfunc AutoRender(w http.ResponseWriter, data interface{}, err error) {\n\tif err != nil {\n\t\tRenderMsgJson(w, err.Error())\n\t\treturn\n\t}\n\tRenderDataJson(w, data)\n}\n\nfunc StdRender(w http.ResponseWriter, data interface{}, err error) {\n\tif err != nil {\n\t\tw.WriteHeader(400)\n\t\tRenderMsgJson(w, err.Error())\n\t\treturn\n\t}\n\tRenderJson(w, data)\n}\n\nfunc postByJson(rw http.ResponseWriter, req *http.Request, url string) {\n\tbuf := new(bytes.Buffer)\n\tbuf.ReadFrom(req.Body)\n\ts := buf.String()\n\treqPost, err := http.NewRequest(\"POST\", url, bytes.NewBuffer([]byte(s)))\n\tif err != nil {\n\t\tlog.Println(\"Error =\", err.Error())\n\t}\n\treqPost.Header.Set(\"Content-Type\", \"application/json\")\n\n\tclient := &http.Client{}\n\tresp, err := client.Do(reqPost)\n\tif err != nil {\n\t\tlog.Println(\"Error =\", err.Error())\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, _ := ioutil.ReadAll(resp.Body)\n\trw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\trw.Write(body)\n}\n\nfunc postByForm(rw http.ResponseWriter, req *http.Request, url string) {\n\treq.ParseForm()\n\tclient := &http.Client{}\n\tresp, err := client.PostForm(url, req.PostForm)\n\tif err != nil {\n\t\tlog.Println(\"Error =\", err.Error())\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, _ := ioutil.ReadAll(resp.Body)\n\trw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\trw.Write(body)\n}\n\nfunc getRequest(rw http.ResponseWriter, url string) {\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\tlog.Println(\"Error =\", err.Error())\n\t}\n\n\tclient := &http.Client{}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\tlog.Println(\"Error =\", err.Error())\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, _ := ioutil.ReadAll(resp.Body)\n\trw.Header().Set(\"Content-Type\", \"application/json; charset=UTF-8\")\n\trw.Write(body)\n}\n"
  },
  {
    "path": "modules/transfer/http/proc_http.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage http\n\nimport (\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/proc\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/sender\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc configProcHttpRoutes() {\n\t// counter\n\thttp.HandleFunc(\"/counter/all\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, proc.GetAll())\n\t})\n\n\t// TO BE DISCARDed\n\thttp.HandleFunc(\"/statistics/all\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, proc.GetAll())\n\t})\n\n\t// step\n\thttp.HandleFunc(\"/proc/step\", func(w http.ResponseWriter, r *http.Request) {\n\t\tRenderDataJson(w, map[string]interface{}{\"min_step\": sender.MinStep})\n\t})\n\n\t// trace\n\thttp.HandleFunc(\"/trace/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/trace/\"):]\n\t\targs := strings.Split(urlParam, \"/\")\n\n\t\targsLen := len(args)\n\t\tendpoint := args[0]\n\t\tmetric := args[1]\n\t\ttags := make(map[string]string)\n\t\tif argsLen > 2 {\n\t\t\ttagVals := strings.Split(args[2], \",\")\n\t\t\tfor _, tag := range tagVals {\n\t\t\t\ttagPairs := strings.Split(tag, \"=\")\n\t\t\t\tif len(tagPairs) == 2 {\n\t\t\t\t\ttags[tagPairs[0]] = tagPairs[1]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tproc.RecvDataTrace.SetPK(cutils.PK(endpoint, metric, tags))\n\t\tRenderDataJson(w, proc.RecvDataTrace.GetAllTraced())\n\t})\n\n\t// filter\n\thttp.HandleFunc(\"/filter/\", func(w http.ResponseWriter, r *http.Request) {\n\t\turlParam := r.URL.Path[len(\"/filter/\"):]\n\t\targs := strings.Split(urlParam, \"/\")\n\n\t\targsLen := len(args)\n\t\tendpoint := args[0]\n\t\tmetric := args[1]\n\t\topt := args[2]\n\n\t\tthreadholdStr := args[3]\n\t\tthreadhold, err := strconv.ParseFloat(threadholdStr, 64)\n\t\tif err != nil {\n\t\t\tRenderDataJson(w, \"bad threadhold\")\n\t\t\treturn\n\t\t}\n\n\t\ttags := make(map[string]string)\n\t\tif argsLen > 4 {\n\t\t\ttagVals := strings.Split(args[4], \",\")\n\t\t\tfor _, tag := range tagVals {\n\t\t\t\ttagPairs := strings.Split(tag, \"=\")\n\t\t\t\tif len(tagPairs) == 2 {\n\t\t\t\t\ttags[tagPairs[0]] = tagPairs[1]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\terr = proc.RecvDataFilter.SetFilter(cutils.PK(endpoint, metric, tags), opt, threadhold)\n\t\tif err != nil {\n\t\t\tRenderDataJson(w, err.Error())\n\t\t\treturn\n\t\t}\n\n\t\tRenderDataJson(w, proc.RecvDataFilter.GetAllFiltered())\n\t})\n}\n"
  },
  {
    "path": "modules/transfer/main.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/http\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/proc\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/receiver\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/sender\"\n\t\"os\"\n)\n\nfunc main() {\n\tg.BinaryName = BinaryName\n\tg.Version = Version\n\tg.GitCommit = GitCommit\n\n\tcfg := flag.String(\"c\", \"cfg.json\", \"configuration file\")\n\tversion := flag.Bool(\"v\", false, \"show version\")\n\tversionGit := flag.Bool(\"vg\", false, \"show version\")\n\tflag.Parse()\n\n\tif *version {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\tif *versionGit {\n\t\tfmt.Printf(\"Open-Falcon %s version %s, build %s\\n\", BinaryName, Version, GitCommit)\n\t\tos.Exit(0)\n\t}\n\n\t// global config\n\tg.ParseConfig(*cfg)\n\t// proc\n\tproc.Start()\n\n\tsender.Start()\n\treceiver.Start()\n\n\t// http\n\thttp.Start()\n\n\tselect {}\n}\n"
  },
  {
    "path": "modules/transfer/proc/proc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage proc\n\nimport (\n\t\"log\"\n\n\tnproc \"github.com/toolkits/proc\"\n)\n\n// trace\nvar (\n\tRecvDataTrace = nproc.NewDataTrace(\"RecvDataTrace\", 3)\n)\n\n// filter\nvar (\n\tRecvDataFilter = nproc.NewDataFilter(\"RecvDataFilter\", 5)\n)\n\n// 统计指标的整体数据\nvar (\n\t// 计数统计,正确计数,错误计数, ...\n\tRecvCnt       = nproc.NewSCounterQps(\"RecvCnt\")\n\tRpcRecvCnt    = nproc.NewSCounterQps(\"RpcRecvCnt\")\n\tHttpRecvCnt   = nproc.NewSCounterQps(\"HttpRecvCnt\")\n\tSocketRecvCnt = nproc.NewSCounterQps(\"SocketRecvCnt\")\n\n\tSendToJudgeCnt    = nproc.NewSCounterQps(\"SendToJudgeCnt\")\n\tSendToTsdbCnt     = nproc.NewSCounterQps(\"SendToTsdbCnt\")\n\tSendToGraphCnt    = nproc.NewSCounterQps(\"SendToGraphCnt\")\n\tSendToTransferCnt = nproc.NewSCounterQps(\"SendToTransferCnt\")\n\tSendToInfluxdbCnt = nproc.NewSCounterQps(\"SendToInfluxdbCnt\")\n\tSendToP8sRelayCnt = nproc.NewSCounterQps(\"SendToP8sRelayCnt\")\n\n\tSendToJudgeDropCnt    = nproc.NewSCounterQps(\"SendToJudgeDropCnt\")\n\tSendToTsdbDropCnt     = nproc.NewSCounterQps(\"SendToTsdbDropCnt\")\n\tSendToGraphDropCnt    = nproc.NewSCounterQps(\"SendToGraphDropCnt\")\n\tSendToTransferDropCnt = nproc.NewSCounterQps(\"SendToTransferDropCnt\")\n\tSendToInfluxdbDropCnt = nproc.NewSCounterQps(\"SendToInfluxdbDropCnt\")\n\tSendToP8sRelayDropCnt = nproc.NewSCounterQps(\"SendToP8sRelayDropCnt\")\n\n\tSendToJudgeFailCnt    = nproc.NewSCounterQps(\"SendToJudgeFailCnt\")\n\tSendToTsdbFailCnt     = nproc.NewSCounterQps(\"SendToTsdbFailCnt\")\n\tSendToGraphFailCnt    = nproc.NewSCounterQps(\"SendToGraphFailCnt\")\n\tSendToTransferFailCnt = nproc.NewSCounterQps(\"SendToTransferFailCnt\")\n\tSendToInfluxdbFailCnt = nproc.NewSCounterQps(\"SendToInfluxdbFailCnt\")\n\tSendToP8sRelayFailCnt = nproc.NewSCounterQps(\"SendToP8sRelayFailCnt\")\n\n\t// 发送缓存大小\n\tJudgeQueuesCnt    = nproc.NewSCounterBase(\"JudgeSendCacheCnt\")\n\tTsdbQueuesCnt     = nproc.NewSCounterBase(\"TsdbSendCacheCnt\")\n\tGraphQueuesCnt    = nproc.NewSCounterBase(\"GraphSendCacheCnt\")\n\tTransferQueuesCnt = nproc.NewSCounterBase(\"TransferSendCacheCnt\")\n\tP8sRelayQueuesCnt = nproc.NewSCounterBase(\"P8sRelaySendCacheCnt\")\n\n\t// http请求次数\n\tHistoryRequestCnt = nproc.NewSCounterQps(\"HistoryRequestCnt\")\n\tInfoRequestCnt    = nproc.NewSCounterQps(\"InfoRequestCnt\")\n\tLastRequestCnt    = nproc.NewSCounterQps(\"LastRequestCnt\")\n\tLastRawRequestCnt = nproc.NewSCounterQps(\"LastRawRequestCnt\")\n\n\t// http回执的监控数据条数\n\tHistoryResponseCounterCnt = nproc.NewSCounterQps(\"HistoryResponseCounterCnt\")\n\tHistoryResponseItemCnt    = nproc.NewSCounterQps(\"HistoryResponseItemCnt\")\n\tLastRequestItemCnt        = nproc.NewSCounterQps(\"LastRequestItemCnt\")\n\tLastRawRequestItemCnt     = nproc.NewSCounterQps(\"LastRawRequestItemCnt\")\n)\n\nfunc Start() {\n\tlog.Println(\"proc.Start, ok\")\n}\n\nfunc GetAll() []interface{} {\n\tret := make([]interface{}, 0)\n\n\t// recv cnt\n\tret = append(ret, RecvCnt.Get())\n\tret = append(ret, RpcRecvCnt.Get())\n\tret = append(ret, HttpRecvCnt.Get())\n\tret = append(ret, SocketRecvCnt.Get())\n\n\t// send cnt\n\tret = append(ret, SendToJudgeCnt.Get())\n\tret = append(ret, SendToTsdbCnt.Get())\n\tret = append(ret, SendToInfluxdbCnt.Get())\n\tret = append(ret, SendToGraphCnt.Get())\n\tret = append(ret, SendToTransferCnt.Get())\n\tret = append(ret, SendToP8sRelayCnt.Get())\n\n\t// drop cnt\n\tret = append(ret, SendToJudgeDropCnt.Get())\n\tret = append(ret, SendToTsdbDropCnt.Get())\n\tret = append(ret, SendToGraphDropCnt.Get())\n\tret = append(ret, SendToTransferDropCnt.Get())\n\tret = append(ret, SendToInfluxdbDropCnt.Get())\n\tret = append(ret, SendToP8sRelayDropCnt.Get())\n\n\t// send fail cnt\n\tret = append(ret, SendToJudgeFailCnt.Get())\n\tret = append(ret, SendToTsdbFailCnt.Get())\n\tret = append(ret, SendToGraphFailCnt.Get())\n\tret = append(ret, SendToTransferFailCnt.Get())\n\tret = append(ret, SendToInfluxdbFailCnt.Get())\n\tret = append(ret, SendToP8sRelayFailCnt.Get())\n\n\t// cache cnt\n\tret = append(ret, JudgeQueuesCnt.Get())\n\tret = append(ret, TsdbQueuesCnt.Get())\n\tret = append(ret, GraphQueuesCnt.Get())\n\tret = append(ret, TransferQueuesCnt.Get())\n\tret = append(ret, P8sRelayQueuesCnt.Get())\n\n\t// http request\n\tret = append(ret, HistoryRequestCnt.Get())\n\tret = append(ret, InfoRequestCnt.Get())\n\tret = append(ret, LastRequestCnt.Get())\n\tret = append(ret, LastRawRequestCnt.Get())\n\n\t// http response\n\tret = append(ret, HistoryResponseCounterCnt.Get())\n\tret = append(ret, HistoryResponseItemCnt.Get())\n\tret = append(ret, LastRequestItemCnt.Get())\n\tret = append(ret, LastRawRequestItemCnt.Get())\n\n\treturn ret\n}\n"
  },
  {
    "path": "modules/transfer/receiver/receiver.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage receiver\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/receiver/rpc\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/receiver/socket\"\n)\n\nfunc Start() {\n\tgo rpc.StartRpc()\n\tgo socket.StartSocket()\n}\n"
  },
  {
    "path": "modules/transfer/receiver/rpc/rpc.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rpc\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"log\"\n\t\"net\"\n\t\"net/rpc\"\n\t\"net/rpc/jsonrpc\"\n)\n\nfunc StartRpc() {\n\tif !g.Config().Rpc.Enabled {\n\t\treturn\n\t}\n\n\taddr := g.Config().Rpc.Listen\n\ttcpAddr, err := net.ResolveTCPAddr(\"tcp\", addr)\n\tif err != nil {\n\t\tlog.Fatalf(\"net.ResolveTCPAddr fail: %s\", err)\n\t}\n\n\tlistener, err := net.ListenTCP(\"tcp\", tcpAddr)\n\tif err != nil {\n\t\tlog.Fatalf(\"listen %s fail: %s\", addr, err)\n\t} else {\n\t\tlog.Println(\"rpc listening\", addr)\n\t}\n\n\tserver := rpc.NewServer()\n\tserver.Register(new(Transfer))\n\n\tfor {\n\t\tconn, err := listener.AcceptTCP()\n\t\tif err != nil {\n\t\t\tlog.Println(\"listener.Accept occur error:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tconn.SetKeepAlive(true)\n\t\tgo server.ServeCodec(jsonrpc.NewServerCodec(conn))\n\t}\n}\n"
  },
  {
    "path": "modules/transfer/receiver/rpc/rpc_transfer.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage rpc\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/proc\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/sender\"\n)\n\ntype Transfer int\n\ntype TransferResp struct {\n\tMsg        string\n\tTotal      int\n\tErrInvalid int\n\tLatency    int64\n}\n\nfunc (t *TransferResp) String() string {\n\ts := fmt.Sprintf(\"TransferResp total=%d, err_invalid=%d, latency=%dms\",\n\t\tt.Total, t.ErrInvalid, t.Latency)\n\tif t.Msg != \"\" {\n\t\ts = fmt.Sprintf(\"%s, msg=%s\", s, t.Msg)\n\t}\n\treturn s\n}\n\nfunc (this *Transfer) Ping(req cmodel.NullRpcRequest, resp *cmodel.SimpleRpcResponse) error {\n\treturn nil\n}\n\nfunc (t *Transfer) Update(args []*cmodel.MetricValue, reply *cmodel.TransferResponse) error {\n\treturn RecvMetricValues(args, reply, \"rpc\")\n}\n\n// process new metric values\nfunc RecvMetricValues(args []*cmodel.MetricValue, reply *cmodel.TransferResponse, from string) error {\n\tstart := time.Now()\n\treply.Invalid = 0\n\n\titems := []*cmodel.MetaData{}\n\tfor _, v := range args {\n\t\tif v == nil {\n\t\t\treply.Invalid += 1\n\t\t\tcontinue\n\t\t}\n\n\t\t// 历史遗留问题.\n\t\t// 老版本agent上报的metric=kernel.hostname的数据,其取值为string类型,现在已经不支持了;所以,这里硬编码过滤掉\n\t\tif v.Metric == \"kernel.hostname\" {\n\t\t\treply.Invalid += 1\n\t\t\tcontinue\n\t\t}\n\n\t\tif v.Metric == \"\" || v.Endpoint == \"\" {\n\t\t\treply.Invalid += 1\n\t\t\tcontinue\n\t\t}\n\n\t\tif v.Type != g.COUNTER && v.Type != g.GAUGE && v.Type != g.DERIVE {\n\t\t\treply.Invalid += 1\n\t\t\tcontinue\n\t\t}\n\n\t\tif v.Value == \"\" {\n\t\t\treply.Invalid += 1\n\t\t\tcontinue\n\t\t}\n\n\t\tif v.Step <= 0 {\n\t\t\treply.Invalid += 1\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(v.Metric)+len(v.Tags) > 510 {\n\t\t\treply.Invalid += 1\n\t\t\tcontinue\n\t\t}\n\n\t\t// TODO 呵呵,这里需要再优雅一点\n\t\tnow := start.Unix()\n\t\tif v.Timestamp <= 0 || v.Timestamp > now*2 {\n\t\t\tv.Timestamp = now\n\t\t}\n\n\t\tfv := &cmodel.MetaData{\n\t\t\tMetric:      v.Metric,\n\t\t\tEndpoint:    v.Endpoint,\n\t\t\tTimestamp:   v.Timestamp,\n\t\t\tStep:        v.Step,\n\t\t\tCounterType: v.Type,\n\t\t\tTags:        cutils.DictedTagstring(v.Tags), //TODO tags键值对的个数,要做一下限制\n\t\t}\n\n\t\tvalid := true\n\t\tvar vv float64\n\t\tvar err error\n\n\t\tswitch cv := v.Value.(type) {\n\t\tcase string:\n\t\t\tvv, err = strconv.ParseFloat(cv, 64)\n\t\t\tif err != nil {\n\t\t\t\tvalid = false\n\t\t\t}\n\t\tcase float64:\n\t\t\tvv = cv\n\t\tcase int64:\n\t\t\tvv = float64(cv)\n\t\tdefault:\n\t\t\tvalid = false\n\t\t}\n\n\t\tif !valid {\n\t\t\treply.Invalid += 1\n\t\t\tcontinue\n\t\t}\n\n\t\tfv.Value = vv\n\t\titems = append(items, fv)\n\t}\n\n\t// statistics\n\tcnt := int64(len(items))\n\tproc.RecvCnt.IncrBy(cnt)\n\tif from == \"rpc\" {\n\t\tproc.RpcRecvCnt.IncrBy(cnt)\n\t} else if from == \"http\" {\n\t\tproc.HttpRecvCnt.IncrBy(cnt)\n\t}\n\n\tcfg := g.Config()\n\n\tif cfg.Graph.Enabled {\n\t\tsender.Push2GraphSendQueue(items)\n\t}\n\n\tif cfg.Judge.Enabled {\n\t\tsender.Push2JudgeSendQueue(items)\n\t}\n\n\tif cfg.Tsdb.Enabled {\n\t\tsender.Push2TsdbSendQueue(items)\n\t}\n\n\tif cfg.Transfer.Enabled {\n\t\tsender.Push2TransferSendQueue(items)\n\t}\n\n\tif cfg.Influxdb.Enabled {\n\t\tsender.Push2InfluxdbSendQueue(items)\n\t}\n\n\tif cfg.P8sRelay.Enabled {\n\t\tsender.Push2P8sRelaySendQueue(items)\n\t}\n\n\treply.Message = \"ok\"\n\treply.Total = len(args)\n\treply.Latency = (time.Now().UnixNano() - start.UnixNano()) / 1000000\n\n\treturn nil\n}\n"
  },
  {
    "path": "modules/transfer/receiver/socket/socket.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage socket\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"log\"\n\t\"net\"\n)\n\nfunc StartSocket() {\n\tif !g.Config().Socket.Enabled {\n\t\treturn\n\t}\n\n\taddr := g.Config().Socket.Listen\n\ttcpAddr, err := net.ResolveTCPAddr(\"tcp\", addr)\n\tif err != nil {\n\t\tlog.Fatalf(\"net.ResolveTCPAddr fail: %s\", err)\n\t}\n\n\tlistener, err := net.ListenTCP(\"tcp\", tcpAddr)\n\tif err != nil {\n\t\tlog.Fatalf(\"listen %s fail: %s\", addr, err)\n\t} else {\n\t\tlog.Println(\"socket listening\", addr)\n\t}\n\n\tdefer listener.Close()\n\n\tfor {\n\t\tconn, err := listener.AcceptTCP()\n\t\tif err != nil {\n\t\t\tlog.Println(\"listener.Accept occur error:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tconn.SetKeepAlive(true)\n\t\tgo socketTelnetHandle(conn)\n\t}\n}\n"
  },
  {
    "path": "modules/transfer/receiver/socket/socket_telnet.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage socket\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/proc\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/sender\"\n)\n\nfunc socketTelnetHandle(conn net.Conn) {\n\tdefer conn.Close()\n\n\titems := []*cmodel.MetaData{}\n\tbuf := bufio.NewReader(conn)\n\n\tcfg := g.Config()\n\ttimeout := time.Duration(cfg.Socket.Timeout) * time.Second\n\n\tfor {\n\t\tconn.SetReadDeadline(time.Now().Add(timeout))\n\t\tline, err := buf.ReadString('\\n')\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\n\t\tline = strings.Trim(line, \"\\n\")\n\n\t\tif line == \"quit\" {\n\t\t\tbreak\n\t\t}\n\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tt := strings.Fields(line)\n\t\tif len(t) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tcmd := t[0]\n\n\t\tif cmd != \"update\" {\n\t\t\tcontinue\n\t\t}\n\n\t\titem, err := convertLine2MetaData(t[1:])\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\titems = append(items, item)\n\t}\n\n\t// statistics\n\tproc.SocketRecvCnt.IncrBy(int64(len(items)))\n\tproc.RecvCnt.IncrBy(int64(len(items)))\n\n\tif cfg.Graph.Enabled {\n\t\tsender.Push2GraphSendQueue(items)\n\t}\n\n\tif cfg.Judge.Enabled {\n\t\tsender.Push2JudgeSendQueue(items)\n\t}\n\n\tif cfg.Transfer.Enabled {\n\t\tsender.Push2TransferSendQueue(items)\n\t}\n\n\tif cfg.P8sRelay.Enabled {\n\t\tsender.Push2P8sRelaySendQueue(items)\n\t}\n\n\treturn\n\n}\n\n// example: endpoint counter timestamp value [type] [step]\n// default type is DERIVE, default step is 60s\nfunc convertLine2MetaData(fields []string) (item *cmodel.MetaData, err error) {\n\tif len(fields) != 4 && len(fields) != 5 && len(fields) != 6 {\n\t\terr = fmt.Errorf(\"not_enough_fileds\")\n\t\treturn\n\t}\n\n\tendpoint, metric := fields[0], fields[1]\n\tts, err := strconv.ParseInt(fields[2], 10, 64)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tv, err := strconv.ParseFloat(fields[3], 64)\n\tif err != nil {\n\t\treturn\n\t}\n\n\ttype_ := g.COUNTER\n\tif len(fields) >= 5 {\n\t\ttype_ = fields[4]\n\t}\n\n\tif type_ != g.DERIVE && type_ != g.GAUGE && type_ != g.COUNTER {\n\t\terr = fmt.Errorf(\"invalid_counter_type\")\n\t\treturn\n\t}\n\n\tvar step int64 = g.DEFAULT_STEP\n\tif len(fields) == 6 {\n\t\tdst_args := strings.Split(fields[5], \":\")\n\t\tif len(dst_args) == 1 {\n\t\t\tstep, err = strconv.ParseInt(dst_args[0], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t} else if len(dst_args) == 4 {\n\t\t\t// for backend-compatible\n\t\t\t// heartbeat:min:max:step\n\t\t\tstep, err = strconv.ParseInt(dst_args[3], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"invalid_counter_step\")\n\t\t\treturn\n\t\t}\n\t}\n\n\titem = &cmodel.MetaData{\n\t\tMetric:      metric,\n\t\tEndpoint:    endpoint,\n\t\tTimestamp:   ts,\n\t\tStep:        step,\n\t\tValue:       v,\n\t\tCounterType: type_,\n\t\tTags:        make(map[string]string),\n\t}\n\n\treturn item, nil\n}\n"
  },
  {
    "path": "modules/transfer/scripts/info",
    "content": "#!/bin/bash\nif [ $# != 2 ];then\n    printf \"format:./query \\\"endpoint\\\" \\\"counter\\\"\\n\"\n    exit 1\nfi\n\n# args\nendpoint=$1\ncounter=$2\n\n# form request body\nreq=\"[{\\\"endpoint\\\":\\\"$endpoint\\\", \\\"counter\\\":\\\"$counter\\\"}]\"\n\n# request \nurl=\"http://127.0.0.1:9966/graph/info\"\ncurl -s -X POST -d \"$req\" \"$url\" | python -m json.tool\n"
  },
  {
    "path": "modules/transfer/scripts/info.py",
    "content": "import requests\n# Copyright 2017 Xiaomi, Inc.\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\nimport json\n\nd = [\n            {\n                \"endpoint\": \"hh-op-mon-tran01.bj\",\n                \"counter\": \"load.15min\",\n            },\n            {\n                \"endpoint\": \"hh-op-mon-tran01.bj\",\n                \"counter\": \"net.if.in.bytes/iface=eth0\",\n            },\n            {\n                \"endpoint\": \"10.202.31.14:7934\",\n                \"counter\": \"p2-com.xiaomi.miui.mibi.service.MibiService-method-createTradeV1\",\n            },\n]\n\nurl = \"http://query.falcon.miliao.srv:9966/graph/info\"\nr = requests.post(url, data=json.dumps(d))\nprint r.text\n\n#curl \"localhost:9966/graph/info/one?endpoint=`hostname`&counter=load.1min\" |python -m json.tool\n"
  },
  {
    "path": "modules/transfer/scripts/last",
    "content": "#!/bin/bash\nif [ $# != 2 ];then\n    printf \"format:./last \\\"endpoint\\\" \\\"counter\\\"\\n\"\n    exit 1\nfi\n\n# args\nendpoint=$1\ncounter=$2\n\n# form request body\nreq=\"[{\\\"endpoint\\\":\\\"$endpoint\\\", \\\"counter\\\":\\\"$counter\\\"}]\"\n\n# request \nurl=\"http://127.0.0.1:9966/graph/last\"\ncurl -s -X POST -d \"$req\" \"$url\" | python -m json.tool\n"
  },
  {
    "path": "modules/transfer/scripts/last_raw",
    "content": "#!/bin/bash\nif [ $# != 2 ];then\n    printf \"format:./last_raw \\\"endpoint\\\" \\\"counter\\\"\\n\"\n    exit 1\nfi\n\n# args\nendpoint=$1\ncounter=$2\n\n# form request body\nreq=\"[{\\\"endpoint\\\":\\\"$endpoint\\\", \\\"counter\\\":\\\"$counter\\\"}]\"\n\n# request \nurl=\"http://127.0.0.1:9966/graph/last/raw\"\ncurl -s -X POST -d \"$req\" \"$url\" | python -m json.tool\n"
  },
  {
    "path": "modules/transfer/scripts/query",
    "content": "#!/bin/bash\nif [ $# != 2 ];then\n    printf \"format:./query \\\"endpoint\\\" \\\"counter\\\"\\n\"\n    exit 1\nfi\n\n# args\nendpoint=$1\ncounter=$2\ncf=\"AVERAGE\"\n\n# form request body\nend_ts=`date +%s`\nstart_ts=`expr $end_ts - 180`\nreq=\"{\\\"start\\\":$start_ts, \\\"end\\\":$end_ts, \\\"cf\\\":\\\"$cf\\\", \\\"endpoint_counters\\\": [{\\\"endpoint\\\":\\\"$endpoint\\\", \\\"counter\\\":\\\"$counter\\\"}]}\"\n\n# request \nurl=\"http://127.0.0.1:9966/graph/history\"\ncurl -s -X POST -d \"$req\" \"$url\" | python -m json.tool\n"
  },
  {
    "path": "modules/transfer/scripts/query.py",
    "content": "import requests\n# Copyright 2017 Xiaomi, Inc.\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\nimport time\nimport json\n\nend = int(time.time())\nstart = end - 3600\n\nd = {\n        \"start\": start,\n        \"end\": end,\n        \"cf\": \"AVERAGE\",\n        \"endpoint_counters\": [\n            {\n                \"endpoint\": \"lg-op-mon-onebox01.bj\",\n                \"counter\": \"load.1min\",\n            },\n            {\n                \"endpoint\": \"lg-op-mon-onebox01.bj\",\n                \"counter\": \"load.5min\",\n            },\n            {\n                \"endpoint\": \"lg-op-mon-onebox01.bj\",\n                \"counter\": \"load.15min\",\n            },\n        ],\n}\n\nurl = \"http://localhost:3060/graph/history\"\nr = requests.post(url, data=json.dumps(d))\nprint r.text\n\n#curl \"http://query.falcon.miliao.srv:9966/graph/history/one?cf=AVERAGE&endpoint=`hostname`&start=`date -d '1 hours ago' +%s`&counter=load.1min\" |python -m json.tool\n"
  },
  {
    "path": "modules/transfer/sender/conn_pools.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\tbackend \"github.com/open-falcon/falcon-plus/common/backend_pool\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\tnset \"github.com/toolkits/container/set\"\n)\n\nfunc initConnPools() {\n\tcfg := g.Config()\n\n\t// judge\n\tjudgeInstances := nset.NewStringSet()\n\tfor _, instance := range cfg.Judge.Cluster {\n\t\tjudgeInstances.Add(instance)\n\t}\n\tJudgeConnPools = backend.CreateSafeRpcConnPools(cfg.Judge.MaxConns, cfg.Judge.MaxIdle,\n\t\tcfg.Judge.ConnTimeout, cfg.Judge.CallTimeout, judgeInstances.ToSlice())\n\n\t// tsdb\n\tif cfg.Tsdb.Enabled {\n\t\tTsdbConnPoolHelper = backend.NewTsdbConnPoolHelper(cfg.Tsdb.Address, cfg.Tsdb.MaxConns, cfg.Tsdb.MaxIdle, cfg.Tsdb.ConnTimeout, cfg.Tsdb.CallTimeout)\n\t}\n\n\t// graph\n\tgraphInstances := nset.NewSafeSet()\n\tfor _, nitem := range cfg.Graph.ClusterList {\n\t\tfor _, addr := range nitem.Addrs {\n\t\t\tgraphInstances.Add(addr)\n\t\t}\n\t}\n\tGraphConnPools = backend.CreateSafeRpcConnPools(cfg.Graph.MaxConns, cfg.Graph.MaxIdle,\n\t\tcfg.Graph.ConnTimeout, cfg.Graph.CallTimeout, graphInstances.ToSlice())\n\n\t// Prometheus中继服务\n\tif cfg.P8sRelay.Enabled {\n\t\tp8sRelayInstances := nset.NewStringSet()\n\t\tfor _, instance := range cfg.P8sRelay.Cluster {\n\t\t\tp8sRelayInstances.Add(instance)\n\t\t}\n\t\tP8sRelayConnPools = backend.CreateSafeRpcConnPools(cfg.P8sRelay.MaxConns, cfg.P8sRelay.MaxIdle,\n\t\t\tcfg.P8sRelay.ConnTimeout, cfg.P8sRelay.CallTimeout, p8sRelayInstances.ToSlice())\n\t}\n\n\t// transfer\n\tif cfg.Transfer.Enabled {\n\t\ttransferInstances := nset.NewStringSet()\n\t\tfor hn, instance := range cfg.Transfer.Cluster {\n\t\t\tTransferHostnames = append(TransferHostnames, hn)\n\t\t\tTransferMap[hn] = instance\n\t\t\ttransferInstances.Add(instance)\n\t\t}\n\t\tTransferConnPools = backend.CreateSafeJsonrpcConnPools(cfg.Transfer.MaxConns, cfg.Transfer.MaxIdle,\n\t\t\tcfg.Transfer.ConnTimeout, cfg.Transfer.CallTimeout, transferInstances.ToSlice())\n\t}\n}\n\nfunc DestroyConnPools() {\n\tcfg := g.Config()\n\n\tJudgeConnPools.Destroy()\n\tGraphConnPools.Destroy()\n\n\tif cfg.Tsdb.Enabled {\n\t\tTsdbConnPoolHelper.Destroy()\n\t}\n\n\tif cfg.Transfer.Enabled {\n\t\tTransferConnPools.Destroy()\n\t}\n}\n"
  },
  {
    "path": "modules/transfer/sender/node_rings.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\trings \"github.com/toolkits/consistent/rings\"\n)\n\nfunc initNodeRings() {\n\tcfg := g.Config()\n\n\tJudgeNodeRing = rings.NewConsistentHashNodesRing(int32(cfg.Judge.Replicas), cutils.KeysOfMap(cfg.Judge.Cluster))\n\tGraphNodeRing = rings.NewConsistentHashNodesRing(int32(cfg.Graph.Replicas), cutils.KeysOfMap(cfg.Graph.Cluster))\n\tP8sRelayNodeRing = rings.NewConsistentHashNodesRing(int32(cfg.P8sRelay.Replicas), cutils.KeysOfMap(cfg.P8sRelay.Cluster))\n}\n"
  },
  {
    "path": "modules/transfer/sender/send_queues.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\tnlist \"github.com/toolkits/container/list\"\n)\n\nfunc initSendQueues() {\n\tcfg := g.Config()\n\tfor node := range cfg.Judge.Cluster {\n\t\tQ := nlist.NewSafeListLimited(DefaultSendQueueMaxSize)\n\t\tJudgeQueues[node] = Q\n\t}\n\n\tfor node, nitem := range cfg.Graph.ClusterList {\n\t\tfor _, addr := range nitem.Addrs {\n\t\t\tQ := nlist.NewSafeListLimited(DefaultSendQueueMaxSize)\n\t\t\tGraphQueues[node+addr] = Q\n\t\t}\n\t}\n\n\tif cfg.P8sRelay.Enabled {\n\t\tfor node, nitem := range cfg.P8sRelay.ClusterList {\n\t\t\tfor _, addr := range nitem.Addrs {\n\t\t\t\tQ := nlist.NewSafeListLimited(DefaultSendQueueMaxSize)\n\t\t\t\tP8sRelayQueues[node+addr] = Q\n\t\t\t}\n\t\t}\n\t}\n\n\tif cfg.Tsdb.Enabled {\n\t\tTsdbQueue = nlist.NewSafeListLimited(DefaultSendQueueMaxSize)\n\t}\n\n\tif cfg.Transfer.Enabled {\n\t\tTransferQueue = nlist.NewSafeListLimited(DefaultSendQueueMaxSize)\n\t}\n\n\tif cfg.Influxdb.Enabled {\n\t\tInfluxdbQueue = nlist.NewSafeListLimited(DefaultSendQueueMaxSize)\n\t}\n}\n"
  },
  {
    "path": "modules/transfer/sender/send_tasks.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\t\"math/rand\"\n\t\"time\"\n\n\t\"github.com/juju/errors\"\n\tpfc \"github.com/niean/goperfcounter\"\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\tcutils \"github.com/open-falcon/falcon-plus/common/utils\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/proc\"\n\tnsema \"github.com/toolkits/concurrent/semaphore\"\n\t\"github.com/toolkits/container/list\"\n)\n\n// send\nconst (\n\tDefaultSendTaskSleepInterval = time.Millisecond * 50 //默认睡眠间隔为50ms\n)\n\n// TODO 添加对发送任务的控制,比如stop等\nfunc startSendTasks() {\n\tcfg := g.Config()\n\t// init semaphore\n\tjudgeConcurrent := cfg.Judge.MaxConns\n\tgraphConcurrent := cfg.Graph.MaxConns\n\ttsdbConcurrent := cfg.Tsdb.MaxConns\n\ttransferConcurrent := cfg.Transfer.MaxConns\n\tinfluxdbConcurrent := cfg.Influxdb.MaxConns\n\tp8sRelayConcurrent := cfg.P8sRelay.MaxConns\n\n\tif tsdbConcurrent < 1 {\n\t\ttsdbConcurrent = 1\n\t}\n\n\tif judgeConcurrent < 1 {\n\t\tjudgeConcurrent = 1\n\t}\n\n\tif graphConcurrent < 1 {\n\t\tgraphConcurrent = 1\n\t}\n\n\tif transferConcurrent < 1 {\n\t\ttransferConcurrent = 1\n\t}\n\n\tif influxdbConcurrent < 1 {\n\t\tinfluxdbConcurrent = 1\n\t}\n\n\tif p8sRelayConcurrent < 1 {\n\t\tp8sRelayConcurrent = 1\n\t}\n\n\t// init send go-routines\n\tfor node := range cfg.Judge.Cluster {\n\t\tqueue := JudgeQueues[node]\n\t\tgo forward2JudgeTask(queue, node, judgeConcurrent)\n\t}\n\n\tfor node, nitem := range cfg.Graph.ClusterList {\n\t\tfor _, addr := range nitem.Addrs {\n\t\t\tqueue := GraphQueues[node+addr]\n\t\t\tgo forward2GraphTask(queue, node, addr, graphConcurrent)\n\t\t}\n\t}\n\n\tif cfg.Tsdb.Enabled {\n\t\tgo forward2TsdbTask(tsdbConcurrent)\n\t}\n\n\tif cfg.Transfer.Enabled {\n\t\tconcurrent := transferConcurrent * len(cfg.Transfer.Cluster)\n\t\tgo forward2TransferTask(TransferQueue, concurrent)\n\t}\n\n\tif cfg.Influxdb.Enabled {\n\t\tgo forward2InfluxdbTask(influxdbConcurrent)\n\t}\n\n\tif cfg.P8sRelay.Enabled {\n\t\tfor node, nitem := range cfg.P8sRelay.ClusterList {\n\t\t\tfor _, addr := range nitem.Addrs {\n\t\t\t\tqueue := P8sRelayQueues[node+addr]\n\t\t\t\tgo forward2P8sRelayTask(queue, node, addr, p8sRelayConcurrent)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Judge定时任务, 将 Judge发送缓存中的数据 通过rpc连接池 发送到Judge\nfunc forward2JudgeTask(Q *list.SafeListLimited, node string, concurrent int) {\n\tbatch := g.Config().Judge.Batch // 一次发送,最多batch条数据\n\taddr := g.Config().Judge.Cluster[node]\n\tsema := nsema.NewSemaphore(concurrent)\n\n\tfor {\n\t\titems := Q.PopBackBy(batch)\n\t\tcount := len(items)\n\t\tif count == 0 {\n\t\t\ttime.Sleep(DefaultSendTaskSleepInterval)\n\t\t\tcontinue\n\t\t}\n\n\t\tjudgeItems := make([]*cmodel.JudgeItem, count)\n\t\tfor i := 0; i < count; i++ {\n\t\t\tjudgeItems[i] = items[i].(*cmodel.JudgeItem)\n\t\t}\n\n\t\t//\t同步Call + 有限并发 进行发送\n\t\tsema.Acquire()\n\t\tgo func(addr string, judgeItems []*cmodel.JudgeItem, count int) {\n\t\t\tdefer sema.Release()\n\n\t\t\tresp := &cmodel.SimpleRpcResponse{}\n\t\t\tvar err error\n\t\t\tsendOk := false\n\t\t\tfor i := 0; i < 3; i++ { //最多重试3次\n\t\t\t\terr = JudgeConnPools.Call(addr, \"Judge.Send\", judgeItems, resp)\n\t\t\t\tif err == nil {\n\t\t\t\t\tsendOk = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ttime.Sleep(time.Millisecond * 10)\n\t\t\t}\n\n\t\t\t// statistics\n\t\t\tif !sendOk {\n\t\t\t\tlog.Printf(\"send judge %s:%s fail: %v\", node, addr, err)\n\t\t\t\tproc.SendToJudgeFailCnt.IncrBy(int64(count))\n\t\t\t} else {\n\t\t\t\tproc.SendToJudgeCnt.IncrBy(int64(count))\n\t\t\t}\n\t\t}(addr, judgeItems, count)\n\t}\n}\n\nfunc forward2P8sRelayTask(Q *list.SafeListLimited, node string, addr string, concurrent int) {\n\tbatch := g.Config().P8sRelay.Batch\n\tsema := nsema.NewSemaphore(concurrent)\n\tfor {\n\t\titems := Q.PopBackBy(batch)\n\t\tcount := len(items)\n\t\tif count == 0 {\n\t\t\ttime.Sleep(DefaultSendTaskSleepInterval)\n\t\t\tcontinue\n\t\t}\n\t\tp8sItems := make([]*cmodel.P8sItem, count)\n\t\tfor i := 0; i < count; i++ {\n\t\t\tp8sItems[i] = items[i].(*cmodel.P8sItem)\n\t\t}\n\n\t\tsema.Acquire()\n\t\tgo func(addr string, p8sItems []*cmodel.P8sItem, count int) {\n\t\t\tdefer sema.Release()\n\t\t\tresp := &cmodel.SimpleRpcResponse{}\n\t\t\tvar err error\n\t\t\tsendOk := false\n\t\t\tfor i := 0; i < 3; i++ {\n\t\t\t\terr = P8sRelayConnPools.Call(addr, \"P8sRelay.Send\", p8sItems, resp)\n\t\t\t\tif err == nil {\n\t\t\t\t\tsendOk = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ttime.Sleep(time.Millisecond * 10)\n\t\t\t}\n\t\t\tif !sendOk {\n\t\t\t\tlog.Printf(\"send p8s relay %s:%s fail: %v\", node, addr, err)\n\t\t\t\tproc.SendToP8sRelayFailCnt.IncrBy(int64(count))\n\t\t\t} else {\n\t\t\t\tproc.SendToP8sRelayCnt.IncrBy(int64(count))\n\t\t\t}\n\t\t}(addr, p8sItems, count)\n\t}\n}\n\n// Graph定时任务, 将 Graph发送缓存中的数据 通过rpc连接池 发送到Graph\nfunc forward2GraphTask(Q *list.SafeListLimited, node string, addr string, concurrent int) {\n\tbatch := g.Config().Graph.Batch // 一次发送,最多batch条数据\n\tsema := nsema.NewSemaphore(concurrent)\n\n\tfor {\n\t\titems := Q.PopBackBy(batch)\n\t\tcount := len(items)\n\t\tif count == 0 {\n\t\t\ttime.Sleep(DefaultSendTaskSleepInterval)\n\t\t\tcontinue\n\t\t}\n\n\t\tgraphItems := make([]*cmodel.GraphItem, count)\n\t\tfor i := 0; i < count; i++ {\n\t\t\tgraphItems[i] = items[i].(*cmodel.GraphItem)\n\t\t}\n\n\t\tsema.Acquire()\n\t\tgo func(addr string, graphItems []*cmodel.GraphItem, count int) {\n\t\t\tdefer sema.Release()\n\n\t\t\tresp := &cmodel.SimpleRpcResponse{}\n\t\t\tvar err error\n\t\t\tsendOk := false\n\t\t\tfor i := 0; i < 3; i++ { //最多重试3次\n\t\t\t\terr = GraphConnPools.Call(addr, \"Graph.Send\", graphItems, resp)\n\t\t\t\tif err == nil {\n\t\t\t\t\tsendOk = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ttime.Sleep(time.Millisecond * 10)\n\t\t\t}\n\n\t\t\t// statistics\n\t\t\tif !sendOk {\n\t\t\t\tlog.Printf(\"send to graph %s:%s fail: %v\", node, addr, err)\n\t\t\t\tproc.SendToGraphFailCnt.IncrBy(int64(count))\n\t\t\t} else {\n\t\t\t\tproc.SendToGraphCnt.IncrBy(int64(count))\n\t\t\t}\n\t\t}(addr, graphItems, count)\n\t}\n}\n\n// Tsdb定时任务, 将数据通过api发送到tsdb\nfunc forward2TsdbTask(concurrent int) {\n\tbatch := g.Config().Tsdb.Batch // 一次发送,最多batch条数据\n\tretry := g.Config().Tsdb.MaxRetry\n\tsema := nsema.NewSemaphore(concurrent)\n\n\tfor {\n\t\titems := TsdbQueue.PopBackBy(batch)\n\t\tif len(items) == 0 {\n\t\t\ttime.Sleep(DefaultSendTaskSleepInterval)\n\t\t\tcontinue\n\t\t}\n\t\t//  同步Call + 有限并发 进行发送\n\t\tsema.Acquire()\n\t\tgo func(itemList []interface{}) {\n\t\t\tdefer sema.Release()\n\n\t\t\tvar tsdbBuffer bytes.Buffer\n\t\t\tcount := len(itemList)\n\t\t\tfor i := 0; i < count; i++ {\n\t\t\t\ttsdbItem := itemList[i].(*cmodel.TsdbItem)\n\t\t\t\ttsdbBuffer.WriteString(tsdbItem.TsdbString())\n\t\t\t\ttsdbBuffer.WriteString(\"\\n\")\n\t\t\t}\n\n\t\t\tvar err error\n\t\t\tfor i := 0; i < retry; i++ {\n\t\t\t\terr = TsdbConnPoolHelper.Send(tsdbBuffer.Bytes())\n\t\t\t\tif err == nil {\n\t\t\t\t\tproc.SendToTsdbCnt.IncrBy(int64(len(itemList)))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\tproc.SendToTsdbFailCnt.IncrBy(int64(len(itemList)))\n\t\t\t\tlog.Println(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}(items)\n\t}\n}\n\n// Transfer定时任务, 将Transfer发送缓存中的数据 通过rpc连接池 发送到Transfer(此时transfer仅仅起到转发数据的功能)\nfunc forward2TransferTask(Q *list.SafeListLimited, concurrent int) {\n\tcfg := g.Config()\n\tbatch := cfg.Transfer.Batch // 一次发送,最多batch条数据\n\tmaxConns := int64(cfg.Transfer.MaxConns)\n\tretry := cfg.Transfer.MaxRetry //最多尝试发送retry次\n\tif retry < 1 {\n\t\tretry = 1\n\t}\n\n\tsema := nsema.NewSemaphore(concurrent)\n\ttransNum := len(TransferHostnames)\n\n\tfor {\n\t\titems := Q.PopBackBy(batch)\n\t\tcount := len(items)\n\t\tif count == 0 {\n\t\t\ttime.Sleep(DefaultSendTaskSleepInterval)\n\t\t\tcontinue\n\t\t}\n\n\t\ttransferItems := make([]*cmodel.MetricValue, count)\n\t\tfor i := 0; i < count; i++ {\n\t\t\ttransferItems[i] = convert(items[i].(*cmodel.MetaData))\n\t\t}\n\n\t\t//\t同步Call + 有限并发 进行发送\n\t\tsema.Acquire()\n\t\tgo func(transferItems []*cmodel.MetricValue, count int) {\n\t\t\tdefer sema.Release()\n\n\t\t\t// 随机遍历transfer列表，直到数据发送成功 或者 遍历完;随机遍历，可以缓解慢transfer\n\t\t\tresp := &cmodel.TransferResponse{}\n\t\t\tvar err error\n\t\t\tsendOk := false\n\n\t\t\tfor j := 0; j < retry && !sendOk; j++ {\n\t\t\t\trint := rand.Int()\n\t\t\t\tfor i := 0; i < transNum && !sendOk; i++ {\n\t\t\t\t\tidx := (i + rint) % transNum\n\t\t\t\t\thost := TransferHostnames[idx]\n\t\t\t\t\taddr := TransferMap[host]\n\n\t\t\t\t\t// 过滤掉建连缓慢的host, 否则会严重影响发送速率\n\t\t\t\t\tcc := pfc.GetCounterCount(host)\n\t\t\t\t\tif cc >= maxConns {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tpfc.Counter(host, 1)\n\t\t\t\t\terr = TransferConnPools.Call(addr, \"Transfer.Update\", transferItems, resp)\n\t\t\t\t\tpfc.Counter(host, -1)\n\n\t\t\t\t\t// statistics\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tsendOk = true\n\t\t\t\t\t\tproc.SendToTransferCnt.IncrBy(int64(count))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlog.Printf(\"transfer update fail, transfer hostname: %s, transfer instance: %s, items size:%d, error:%v, resp:%v\", host, addr, len(transferItems), err, resp)\n\t\t\t\t\t\tproc.SendToTransferFailCnt.IncrBy(int64(count))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}(transferItems, count)\n\t}\n}\n\n// cmodel.MetaData --> cmodel.MetricValue\nfunc convert(v *cmodel.MetaData) *cmodel.MetricValue {\n\treturn &cmodel.MetricValue{\n\t\tMetric:    v.Metric,\n\t\tEndpoint:  v.Endpoint,\n\t\tTimestamp: v.Timestamp,\n\t\tStep:      v.Step,\n\t\tType:      v.CounterType,\n\t\tTags:      cutils.SortedTags(v.Tags),\n\t\tValue:     v.Value,\n\t}\n}\n\nfunc forward2InfluxdbTask(concurrent int) {\n\tbatch := g.Config().Influxdb.Batch // 一次发送,最多batch条数据\n\tretry := g.Config().Influxdb.MaxRetry\n\tsema := nsema.NewSemaphore(concurrent)\n\n\tfor {\n\t\titems := InfluxdbQueue.PopBackBy(batch)\n\t\tif len(items) == 0 {\n\t\t\ttime.Sleep(DefaultSendTaskSleepInterval)\n\t\t\tcontinue\n\t\t}\n\t\t//  同步Call + 有限并发 进行发送\n\t\tsema.Acquire()\n\t\tgo func(itemList []interface{}) {\n\t\t\tdefer sema.Release()\n\n\t\t\tvar err error\n\t\t\tc, err := NewInfluxdbClient()\n\t\t\tdefer c.Client.Close()\n\n\t\t\tif err != nil {\n\t\t\t\tlog.Println(errors.ErrorStack(err))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\titems := make([]*cmodel.InfluxdbItem, 0, batch)\n\t\t\tfor _, i := range itemList {\n\t\t\t\titems = append(items, i.(*cmodel.InfluxdbItem))\n\t\t\t}\n\n\t\t\tfor i := 0; i < retry; i++ {\n\t\t\t\terr = c.Send(items)\n\t\t\t\tif err == nil {\n\t\t\t\t\tproc.SendToInfluxdbCnt.IncrBy(int64(len(itemList)))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\tproc.SendToInfluxdbFailCnt.IncrBy(int64(len(itemList)))\n\t\t\t\tlog.Println(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}(items)\n\t}\n}\n"
  },
  {
    "path": "modules/transfer/sender/sender.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"time\"\n\n\t\"github.com/influxdata/influxdb/client/v2\"\n\tbackend \"github.com/open-falcon/falcon-plus/common/backend_pool\"\n\tcmodel \"github.com/open-falcon/falcon-plus/common/model\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/proc\"\n\trings \"github.com/toolkits/consistent/rings\"\n\tnlist \"github.com/toolkits/container/list\"\n)\n\nconst (\n\tDefaultSendQueueMaxSize = 102400 //10.24w\n)\n\n// 默认参数\nvar (\n\tMinStep int //最小上报周期,单位sec\n)\n\n// 服务节点的一致性哈希环\n// pk -> node\nvar (\n\tJudgeNodeRing    *rings.ConsistentHashNodeRing\n\tGraphNodeRing    *rings.ConsistentHashNodeRing\n\tP8sRelayNodeRing *rings.ConsistentHashNodeRing\n)\n\n// 发送缓存队列\n// node -> queue_of_data\nvar (\n\tTsdbQueue      *nlist.SafeListLimited\n\tJudgeQueues    = make(map[string]*nlist.SafeListLimited)\n\tGraphQueues    = make(map[string]*nlist.SafeListLimited)\n\tP8sRelayQueues = make(map[string]*nlist.SafeListLimited)\n\tTransferQueue  *nlist.SafeListLimited\n\tInfluxdbQueue  *nlist.SafeListLimited\n)\n\n// transfer的主机列表，以及主机名和地址的映射关系\n// 用于随机遍历transfer\nvar (\n\tTransferMap       = make(map[string]string, 0)\n\tTransferHostnames = make([]string, 0)\n)\n\n// 连接池\n// node_address -> connection_pool\nvar (\n\tJudgeConnPools     *backend.SafeRpcConnPools\n\tTsdbConnPoolHelper *backend.TsdbConnPoolHelper\n\tGraphConnPools     *backend.SafeRpcConnPools\n\tTransferConnPools  *backend.SafeRpcConnPools\n\tP8sRelayConnPools  *backend.SafeRpcConnPools\n)\n\n// infludbConn\ntype InfluxClient struct {\n\tClient    client.Client\n\tDatabase  string\n\tPrecision string\n}\n\nfunc NewInfluxdbClient() (*InfluxClient, error) {\n\tc, err := client.NewHTTPClient(client.HTTPConfig{\n\t\tAddr:     g.Config().Influxdb.Address,\n\t\tUsername: g.Config().Influxdb.Username,\n\t\tPassword: g.Config().Influxdb.Password,\n\t\tTimeout:  time.Millisecond * time.Duration(g.Config().Influxdb.Timeout),\n\t})\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &InfluxClient{\n\t\tClient:    c,\n\t\tDatabase:  g.Config().Influxdb.Database,\n\t\tPrecision: g.Config().Influxdb.Precision,\n\t}, nil\n}\n\nfunc (c *InfluxClient) Send(items []*cmodel.InfluxdbItem) error {\n\tbp, err := client.NewBatchPoints(client.BatchPointsConfig{\n\t\tDatabase:  c.Database,\n\t\tPrecision: c.Precision,\n\t})\n\tif err != nil {\n\t\tlog.Println(\"create batch points error: \", err)\n\t\treturn err\n\t}\n\n\tfor _, item := range items {\n\t\tpt, err := client.NewPoint(item.Measurement, item.Tags, item.Fileds, time.Unix(item.Timestamp, 0))\n\t\tif err != nil {\n\t\t\tlog.Println(\"create new points error: \", err)\n\t\t\tcontinue\n\t\t}\n\t\tbp.AddPoint(pt)\n\t}\n\n\treturn c.Client.Write(bp)\n}\n\n// 初始化数据发送服务, 在main函数中调用\nfunc Start() {\n\t// 初始化默认参数\n\tMinStep = g.Config().MinStep\n\tif MinStep < 1 {\n\t\tMinStep = 30 //默认30s\n\t}\n\t//\n\tinitConnPools()\n\tinitSendQueues()\n\tinitNodeRings()\n\t// SendTasks依赖基础组件的初始化,要最后启动\n\tstartSendTasks()\n\tstartSenderCron()\n\tlog.Println(\"send.Start, ok\")\n}\n\n// 将数据 打入 某个Judge的发送缓存队列, 具体是哪一个Judge 由一致性哈希 决定\nfunc Push2JudgeSendQueue(items []*cmodel.MetaData) {\n\tfor _, item := range items {\n\t\tpk := item.PK()\n\t\tnode, err := JudgeNodeRing.GetNode(pk)\n\t\tif err != nil {\n\t\t\tlog.Println(\"E:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// align ts\n\t\tstep := int(item.Step)\n\t\tif step < MinStep {\n\t\t\tstep = MinStep\n\t\t}\n\t\tts := alignTs(item.Timestamp, int64(step))\n\n\t\tjudgeItem := &cmodel.JudgeItem{\n\t\t\tEndpoint:  item.Endpoint,\n\t\t\tMetric:    item.Metric,\n\t\t\tValue:     item.Value,\n\t\t\tTimestamp: ts,\n\t\t\tJudgeType: item.CounterType,\n\t\t\tTags:      item.Tags,\n\t\t}\n\t\tQ := JudgeQueues[node]\n\t\tisSuccess := Q.PushFront(judgeItem)\n\n\t\t// statistics\n\t\tif !isSuccess {\n\t\t\tproc.SendToJudgeDropCnt.Incr()\n\t\t}\n\t}\n}\n\nfunc Push2P8sRelaySendQueue(items []*cmodel.MetaData) {\n\tcfg := g.Config().P8sRelay\n\tnotSyncMetrics := g.Config().P8sRelay.NotSyncMetrics\n\tfor _, item := range items {\n\t\t// 过滤同步到Prometheus的监控指标\n\t\tsync := true\n\t\tfor _, m := range notSyncMetrics {\n\t\t\tif strings.HasPrefix(item.Metric, m) {\n\t\t\t\tsync = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !sync {\n\t\t\tcontinue\n\t\t}\n\t\tp8sItem, err := convert2P8sRelayItem(item)\n\t\tif err != nil {\n\t\t\tlog.Println(\"E:\", err)\n\t\t\tcontinue\n\t\t}\n\t\tpk := item.PK()\n\t\t// statistics\n\t\tproc.RecvDataTrace.Trace(pk, item)\n\t\tproc.RecvDataFilter.Filter(pk, item.Value, item)\n\n\t\tnode, err := P8sRelayNodeRing.GetNode(pk)\n\t\tif err != nil {\n\t\t\tlog.Println(\"E:\", err)\n\t\t\tcontinue\n\t\t}\n\t\tcnode := cfg.ClusterList[node]\n\t\terrCnt := 0\n\t\tfor _, addr := range cnode.Addrs {\n\t\t\tQ := P8sRelayQueues[node+addr]\n\t\t\tif !Q.PushFront(p8sItem) {\n\t\t\t\terrCnt += 1\n\t\t\t}\n\t\t}\n\t\t// statistics\n\t\tif errCnt > 0 {\n\t\t\tproc.SendToP8sRelayDropCnt.Incr()\n\t\t}\n\n\t}\n}\n\n// 将数据 打入 某个Graph的发送缓存队列, 具体是哪一个Graph 由一致性哈希 决定\nfunc Push2GraphSendQueue(items []*cmodel.MetaData) {\n\tcfg := g.Config().Graph\n\n\tfor _, item := range items {\n\t\tgraphItem, err := convert2GraphItem(item)\n\t\tif err != nil {\n\t\t\tlog.Println(\"E:\", err)\n\t\t\tcontinue\n\t\t}\n\t\tpk := item.PK()\n\n\t\t// statistics. 为了效率,放到了这里,因此只有graph是enbale时才能trace\n\t\tproc.RecvDataTrace.Trace(pk, item)\n\t\tproc.RecvDataFilter.Filter(pk, item.Value, item)\n\n\t\tnode, err := GraphNodeRing.GetNode(pk)\n\t\tif err != nil {\n\t\t\tlog.Println(\"E:\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tcnode := cfg.ClusterList[node]\n\t\terrCnt := 0\n\t\tfor _, addr := range cnode.Addrs {\n\t\t\tQ := GraphQueues[node+addr]\n\t\t\tif !Q.PushFront(graphItem) {\n\t\t\t\terrCnt += 1\n\t\t\t}\n\t\t}\n\n\t\t// statistics\n\t\tif errCnt > 0 {\n\t\t\tproc.SendToGraphDropCnt.Incr()\n\t\t}\n\t}\n}\n\nfunc convert2P8sRelayItem(d *cmodel.MetaData) (*cmodel.P8sItem, error) {\n\titem := &cmodel.P8sItem{}\n\n\titem.Endpoint = d.Endpoint\n\titem.Metric = d.Metric\n\titem.Tags = d.Tags\n\titem.Timestamp = d.Timestamp\n\titem.Value, _ = strconv.ParseFloat(fmt.Sprintf(\"%.3f\", d.Value), 64)\n\titem.Step = int(d.Step)\n\tif item.Step < MinStep {\n\t\titem.Step = MinStep\n\t}\n\n\tif d.CounterType == g.GAUGE {\n\t\titem.MetricType = g.GAUGE\n\t} else if d.CounterType == g.COUNTER {\n\t\titem.MetricType = g.COUNTER\n\t} else {\n\t\tlog.Printf(\"Error not supported counter type: %s\", d.CounterType)\n\t\treturn item, fmt.Errorf(\"not_supported_counter_type\")\n\t}\n\n\titem.Timestamp = alignTs(item.Timestamp, int64(item.Step)) //item.Timestamp - item.Timestamp%int64(item.Step)\n\n\treturn item, nil\n}\n\n// 打到Graph的数据,要根据rrdtool的特定 来限制 step、counterType、timestamp\nfunc convert2GraphItem(d *cmodel.MetaData) (*cmodel.GraphItem, error) {\n\titem := &cmodel.GraphItem{}\n\n\titem.Endpoint = d.Endpoint\n\titem.Metric = d.Metric\n\titem.Tags = d.Tags\n\titem.Timestamp = d.Timestamp\n\titem.Value = d.Value\n\titem.Step = int(d.Step)\n\tif item.Step < MinStep {\n\t\titem.Step = MinStep\n\t}\n\titem.Heartbeat = item.Step * 2\n\n\tif d.CounterType == g.GAUGE {\n\t\titem.DsType = d.CounterType\n\t\titem.Min = \"U\"\n\t\titem.Max = \"U\"\n\t} else if d.CounterType == g.COUNTER {\n\t\titem.DsType = g.DERIVE\n\t\titem.Min = \"0\"\n\t\titem.Max = \"U\"\n\t} else if d.CounterType == g.DERIVE {\n\t\titem.DsType = g.DERIVE\n\t\titem.Min = \"0\"\n\t\titem.Max = \"U\"\n\t} else {\n\t\treturn item, fmt.Errorf(\"not_supported_counter_type\")\n\t}\n\n\titem.Timestamp = alignTs(item.Timestamp, int64(item.Step)) //item.Timestamp - item.Timestamp%int64(item.Step)\n\n\treturn item, nil\n}\n\n// 将原始数据入到tsdb发送缓存队列\nfunc Push2TsdbSendQueue(items []*cmodel.MetaData) {\n\tfor _, item := range items {\n\t\ttsdbItem := convert2TsdbItem(item)\n\t\tisSuccess := TsdbQueue.PushFront(tsdbItem)\n\n\t\tif !isSuccess {\n\t\t\tproc.SendToTsdbDropCnt.Incr()\n\t\t}\n\t}\n}\n\n// 转化为tsdb格式\nfunc convert2TsdbItem(d *cmodel.MetaData) *cmodel.TsdbItem {\n\tt := cmodel.TsdbItem{Tags: make(map[string]string)}\n\n\tfor k, v := range d.Tags {\n\t\tt.Tags[k] = v\n\t}\n\tt.Tags[\"endpoint\"] = d.Endpoint\n\tt.Metric = d.Metric\n\tt.Timestamp = d.Timestamp\n\tt.Value = d.Value\n\treturn &t\n}\n\nfunc alignTs(ts int64, period int64) int64 {\n\treturn ts - ts%period\n}\n\nfunc Push2TransferSendQueue(items []*cmodel.MetaData) {\n\tfor _, item := range items {\n\t\tisSuccess := TransferQueue.PushFront(item)\n\n\t\tif !isSuccess {\n\t\t\tproc.SendToTransferDropCnt.Incr()\n\t\t}\n\t}\n}\n\n// 将原始数据插入到influxdb缓存队列\nfunc Push2InfluxdbSendQueue(items []*cmodel.MetaData) {\n\tfor _, item := range items {\n\t\tinfluxdbItem := convert2InfluxdbItem(item)\n\t\tisSuccess := InfluxdbQueue.PushFront(influxdbItem)\n\n\t\tif !isSuccess {\n\t\t\tproc.SendToInfluxdbDropCnt.Incr()\n\t\t}\n\t}\n}\n\nfunc convert2InfluxdbItem(d *cmodel.MetaData) *cmodel.InfluxdbItem {\n\tt := cmodel.InfluxdbItem{Tags: make(map[string]string), Fileds: make(map[string]interface{})}\n\n\tfor k, v := range d.Tags {\n\t\tt.Tags[k] = v\n\t}\n\tt.Tags[\"endpoint\"] = d.Endpoint\n\tt.Measurement = d.Metric\n\tt.Fileds[\"value\"] = d.Value\n\tt.Timestamp = d.Timestamp\n\n\treturn &t\n}\n"
  },
  {
    "path": "modules/transfer/sender/sender_cron.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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\npackage sender\n\nimport (\n\t\"log\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/g\"\n\t\"github.com/open-falcon/falcon-plus/modules/transfer/proc\"\n\t\"github.com/toolkits/container/list\"\n)\n\nconst (\n\tDefaultProcCronPeriod = time.Duration(5) * time.Second    //ProcCron的周期,默认1s\n\tDefaultLogCronPeriod  = time.Duration(3600) * time.Second //LogCron的周期,默认300s\n)\n\n// send_cron程序入口\nfunc startSenderCron() {\n\tgo startProcCron()\n\tgo startLogCron()\n}\n\nfunc startProcCron() {\n\tfor {\n\t\ttime.Sleep(DefaultProcCronPeriod)\n\t\trefreshSendingCacheSize()\n\t}\n}\n\nfunc startLogCron() {\n\tfor {\n\t\ttime.Sleep(DefaultLogCronPeriod)\n\t\tlogConnPoolsProc()\n\t}\n}\n\nfunc refreshSendingCacheSize() {\n\tproc.JudgeQueuesCnt.SetCnt(calcSendCacheSize(JudgeQueues))\n\tproc.GraphQueuesCnt.SetCnt(calcSendCacheSize(GraphQueues))\n\n\tcfg := g.Config()\n\n\tif cfg.Tsdb.Enabled {\n\t\tproc.TsdbQueuesCnt.SetCnt(int64(TsdbQueue.Len()))\n\t}\n\tif cfg.Transfer.Enabled {\n\t\tproc.TransferQueuesCnt.SetCnt(int64(TransferQueue.Len()))\n\t}\n\tif cfg.P8sRelay.Enabled {\n\t\tproc.P8sRelayQueuesCnt.SetCnt(calcSendCacheSize(P8sRelayQueues))\n\t}\n}\n\nfunc calcSendCacheSize(mapList map[string]*list.SafeListLimited) int64 {\n\tvar cnt int64 = 0\n\tfor _, list := range mapList {\n\t\tif list != nil {\n\t\t\tcnt += int64(list.Len())\n\t\t}\n\t}\n\treturn cnt\n}\n\nfunc logConnPoolsProc() {\n\tcfg := g.Config()\n\tlog.Printf(\"judge connPools proc: \\n%v\", strings.Join(JudgeConnPools.Proc(), \"\\n\"))\n\tlog.Printf(\"graph connPools proc: \\n%v\", strings.Join(GraphConnPools.Proc(), \"\\n\"))\n\tif cfg.Transfer.Enabled {\n\t\tlog.Printf(\"transfer connPools proc: \\n%v\", strings.Join(TransferConnPools.Proc(), \"\\n\"))\n\t}\n\tif cfg.P8sRelay.Enabled {\n\t\tlog.Printf(\"p8s_relay connPools proc: \\n%v\", strings.Join(GraphConnPools.Proc(), \"\\n\"))\n\t}\n}\n"
  },
  {
    "path": "modules/transfer/test/debug",
    "content": "#!/bin/bash\n## test home\ntestdir=$(cd $(dirname $0)/; pwd)\n## word home\nworkdir=$(dirname $testdir)\ncd $workdir\n\nmodule=transfer\napp=falcon-$module\npidfile=var/app.pid\nlogfile=var/app.log\ncontrol=./control\nhttpprex=\"127.0.0.1:6060\"\nsockaddr=\"127.0.0.1\"\nsockport=\"4444\"\n\n## statistics\nfunction statistics(){\n    curl -s \"$httpprex/statistics/all\" | python -m json.tool\n}\n\n## config\nfunction config(){\n    action=$1\n    case $action in\n        \"reload\")\n            curl -s \"$httpprex/config/reload\" | python -m json.tool\n            ;;\n        *)\n            curl -s \"$httpprex/config\" | python -m json.tool\n            ;;\n    esac\n}\n\n## status\nfunction conn_pool_status(){\n    m=$1\n    if [ \"X$m\" == \"X\" ]; then\n        m=\"graph\"\n    fi\n    curl -s \"$httpprex/debug/connpool/$m\"\n    printf \"\\n\"\n}\n\n## trace\nfunction trace_recv(){\n    e=\"test.endpoint.niean.1\" \n    m=\"test.metric.niean.1\"\n    t=\"tag0=tag0-niean-1,tag1=tag1-niean-1,tag2=tag2-niean-1\"\n    curl -s \"$httpprex/trace/$e/$m/$t\" | python -m json.tool\n}\n\n## filter\nfunction filter_recv(){\n    e=\"test.endpoint.niean.1\" \n    m=\"test.metric.niean.1\"\n    opt=\"lt\"\n    val=\"5\"\n    t=\"tag0=tag0-niean-1,tag1=tag1-niean-1,tag2=tag2-niean-1\"\n    curl -s \"$httpprex/filter/$e/$m/$opt/$val/$t\" | python -m json.tool\n}\n\n## api\nfunction http_post(){\n    e=\"test.endpoint.niean.1\" \n    m=\"test.metric.niean.1\"\n    t=\"tag0=tag0-niean-1,tag1=tag1-niean-1,tag2=tag2-niean-1\"\n    ts=`date +%s`\n    val=`expr $ts / 60 % 10`\n    curl -s -X POST -d \"[{\\\"metric\\\":\\\"$m\\\", \\\"endpoint\\\":\\\"$e\\\", \\\"timestamp\\\":$ts,\\\"step\\\":60, \\\"value\\\":$val, \\\"counterType\\\":\\\"GAUGE\\\",\\\"tags\\\":\\\"$t\\\"}]\" \"$httpprex/api/push\" | python -m json.tool\n}\n\n\n## telnet \nfunction telnet_send(){\n    cnt=$1\n    if [ \"X$cnt\" == \"X\" ];then\n        cnt=1\n    fi\n\n    e=\"test.endpoint.niean.1\" \n    m=\"test.metric.niean.1\"\n    type=\"GAUGE\"\n    step=60\n     # endpoint counter timestamp value [type] [step]\n    (for i in `seq 1 $cnt`; do echo \"update $e $m `date +%s` $i $type $step\"; sleep 1; done; echo \"quit\") | nc $sockaddr $sockport\n    if [ $? -eq 0 ]; then\n        echo \"ok\"\n    else\n        echo \"error\"\n    fi\n}\n\n## tail\nfunction tail_log(){\n    $control tail\n}\n\n## build\nfunction build(){\n    $control build\n    [ $? -eq 0 ] && echo -e \"build ok\" || { echo -e \"build error\"; exit 1; }\n}\nfunction start(){\n    $control start\n}\nfunction stop(){\n    $control stop\n}\n\n## mockagent\nsrcname=mockagent\nappname=$srcname-debug\nbuilddir=$testdir/build\nmasrc=$testdir/$srcname.go\nmatarget=$builddir/$appname.bin\n\nfunction build_mockagent(){\n\trm -rf $matarget &&\\\n\tgo build -o $matarget $masrc &>/dev/null\n    ec=$?\n    [ $ec -eq 0 ] && echo -e \"mockagent build, ok\" || { echo -e \"mockagent build, error\"; exit $ec;}\n}\n\nfunction clean_mockagent(){\n    rm -rf $builddir  \n    ec=$?\n    [ $ec -eq 0 ] && echo -e \"clean mockagent, ok\" || { echo -e \"clean mockagent, error\"; exit $ec; }\n}\n\nfunction kill_mockagent(){\n    pids=`ps -ef | grep $appname.bin | grep -v grep | awk '{print $2}'`\n    for pid in $pids\n    do\n        kill -9  $pid &>/dev/null\n        echo -e \"kill mockagent, $pid\"\n        sleep 0.01\n    done \n    echo -e \"kill mockagent ok\"\n}\n\nfunction start_mockagent(){\n    cnt=$1\n    if [ \"X$cnt\" == \"X\" ];then\n        cnt=1\n    fi\n    \n    for i in `seq 1 $cnt`\n    do\n        id=malog.`date +%s`\n        $matarget -i 3 > $builddir/$id.$i.log &\n        echo -e \"start mockagent, $id.$i\"\n        sleep 0.2\n    done\n}\n\naction=$1\ncase $action in\n    \"build\")\n        build\n        ;;\n    \"start\")\n        start\n        ;;\n    \"stop\")\n        stop\n        ;;\n    \"restart\")\n        stop && build && start\n        ;;\n    \"config\")\n        config $2\n        ;;\n    \"tail\")\n        tail_log\n        ;;\n    \"trace\")\n        trace_recv \n        ;;\n    \"filter\")\n        filter_recv \n        ;;\n    \"conn\")\n        conn_pool_status $2\n        ;;\n    \"post\")\n        http_post \n        ;;\n    \"send\")\n        telnet_send\n        ;;\n    \"startm\")\n        start_mockagent $2\n        ;;\n    \"killm\")\n        kill_mockagent\n        ;;\n    \"cleanm\")\n        clean_mockagent \n        ;;\n    \"buildm\")\n        build_mockagent\n        ;;\n    *)\n        statistics \n        ;;\nesac\n\n"
  },
  {
    "path": "modules/transfer/test/rpcclient.py",
    "content": "import json\n# Copyright 2017 Xiaomi, Inc.\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\nimport socket\nimport itertools\nimport time\n \nclass RPCClient(object):\n \n    def __init__(self, addr, codec=json):\n        self._socket = socket.create_connection(addr)\n        self._id_iter = itertools.count()\n        self._codec = codec\n \n    def _message(self, name, *params):\n        return dict(id=self._id_iter.next(),\n                    params=list(params),\n                    method=name)\n \n    def call(self, name, *params):\n        req = self._message(name, *params)\n        id = req.get('id')\n \n        mesg = self._codec.dumps(req)\n        self._socket.sendall(mesg)\n \n        # This will actually have to loop if resp is bigger\n        resp = self._socket.recv(4096)\n        resp = self._codec.loads(resp)\n \n        if resp.get('id') != id:\n            raise Exception(\"expected id=%s, received id=%s: %s\"\n                            %(id, resp.get('id'), resp.get('error')))\n \n        if resp.get('error') is not None:\n            raise Exception(resp.get('error'))\n \n        return resp.get('result')\n \n    def close(self):\n        self._socket.close()\n \n\nif __name__ == '__main__':\n    rpc = RPCClient((\"127.0.0.1\", 8433))\n    for i in xrange(10000):\n        mv1 = dict(endpoint='host.niean', metric='metric.niean.1', value=i, step=60, \n            counterType='GAUGE', tags='tag=t'+str(i), timestamp=int(time.time()))\n        mv2 = dict(endpoint='host.niean', metric='metric.niean.2', value=i, step=60, \n            counterType='COUNTER', tags='tag=t'+str(i), timestamp=int(time.time()))\n        print rpc.call(\"Transfer.Update\", [mv1, mv2])\n"
  },
  {
    "path": "modules/transfer/version.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// build !release\npackage main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  },
  {
    "path": "scripts/mysql/.gitignore",
    "content": "*.swp\n*.pyc\n"
  },
  {
    "path": "scripts/mysql/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "scripts/mysql/NOTICE",
    "content": "Open-Falcon\n\nCopyright (c) 2014-2017 Xiaomi, Inc. All Rights Reserved.\n\nThis product is licensed to you under the Apache License, Version 2.0 (the \"License\").\nYou may not use this product except in compliance with the License.\n\nThis product may include a number of subcomponents with separate copyright notices\nand license terms. Your use of these subcomponents is subject to the terms and\nconditions of the subcomponent's license, as noted in the LICENSE file.\n"
  },
  {
    "path": "scripts/mysql/db_schema/1_uic-db-schema.sql",
    "content": "create database uic\n  DEFAULT CHARACTER SET utf8\n  DEFAULT COLLATE utf8_general_ci;\nUSE uic;\nSET NAMES utf8;\n\nDROP TABLE if exists team;\nCREATE TABLE `team` (\n  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `name` varchar(64) NOT NULL,\n  `resume` varchar(255) not null default '',\n  `creator` int(10) unsigned NOT NULL DEFAULT '0',\n  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `idx_team_name` (`name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n/**\n * role: -1:blocked 0:normal 1:admin 2:root\n */\nDROP TABLE if exists `user`;\nCREATE TABLE `user` (\n  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `name` varchar(64) NOT NULL,\n  `passwd` varchar(64) not null default '',\n  `cnname` varchar(128) not null default '',\n  `email` varchar(255) not null default '',\n  `phone` varchar(16) not null default '',\n  `im` varchar(32) not null default '',\n  `qq` varchar(16) not null default '',\n  `role` tinyint not null default 0,\n  `creator` int(10) unsigned NOT NULL DEFAULT 0,\n  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `idx_user_name` (`name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nDROP TABLE if exists `rel_team_user`;\nCREATE TABLE `rel_team_user` (\n  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `tid` int(10) unsigned not null,\n  `uid` int(10) unsigned not null,\n  PRIMARY KEY (`id`),\n  KEY `idx_rel_tid` (`tid`),\n  KEY `idx_rel_uid` (`uid`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nDROP TABLE if exists `session`;\nCREATE TABLE `session` (\n  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `uid` int(10) unsigned not null,\n  `sig` varchar(32) not null,\n  `expired` int(10) unsigned not null,\n  PRIMARY KEY (`id`),\n  KEY `idx_session_uid` (`uid`),\n  KEY `idx_session_sig` (`sig`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n/*900150983cd24fb0d6963f7d28e17f72*/\n/*insert into `user`(`name`, `passwd`, `role`, `created`) values('root', md5('abc'), 2, now());*/\n\n"
  },
  {
    "path": "scripts/mysql/db_schema/2_portal-db-schema.sql",
    "content": "CREATE DATABASE falcon_portal\n  DEFAULT CHARACTER SET utf8\n  DEFAULT COLLATE utf8_general_ci;\nUSE falcon_portal;\nSET NAMES utf8;\n\n/**\n * 这里的机器是从机器管理系统中同步过来的\n * 系统拿出来单独部署需要为hbs增加功能，心跳上来的机器写入host表\n */\nDROP TABLE IF EXISTS host;\nCREATE TABLE host\n(\n  id             INT UNSIGNED NOT NULL AUTO_INCREMENT,\n  hostname       VARCHAR(255) NOT NULL DEFAULT '',\n  ip             VARCHAR(16)  NOT NULL DEFAULT '',\n  agent_version  VARCHAR(16)  NOT NULL DEFAULT '',\n  plugin_version VARCHAR(128) NOT NULL DEFAULT '',\n  maintain_begin INT UNSIGNED NOT NULL DEFAULT 0,\n  maintain_end   INT UNSIGNED NOT NULL DEFAULT 0,\n  update_at      TIMESTAMP    NOT NULL DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,\n  PRIMARY KEY (id),\n  UNIQUE KEY idx_host_hostname (hostname)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\n\n/**\n * 机器分组信息\n * come_from 0: 从机器管理同步过来的；1: 从页面创建的\n */\nDROP TABLE IF EXISTS grp;\nCREATE TABLE `grp` (\n  id          INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,\n  grp_name    VARCHAR(255)     NOT NULL DEFAULT '',\n  create_user VARCHAR(64)      NOT NULL DEFAULT '',\n  create_at   TIMESTAMP        NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  come_from   TINYINT(4)       NOT NULL DEFAULT '0',\n  PRIMARY KEY (id),\n  UNIQUE KEY idx_host_grp_grp_name (grp_name)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\n\nDROP TABLE IF EXISTS grp_host;\nCREATE TABLE grp_host\n(\n  grp_id  INT UNSIGNED NOT NULL,\n  host_id INT UNSIGNED NOT NULL,\n  KEY idx_grp_host_grp_id (grp_id),\n  KEY idx_grp_host_host_id (host_id)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\n\n/**\n * 监控策略模板\n * tpl_name全局唯一，命名的时候可以适当带上一些前缀，比如：sa.falcon.base\n */\nDROP TABLE IF EXISTS tpl;\nCREATE TABLE tpl\n(\n  id          INT UNSIGNED NOT NULL AUTO_INCREMENT,\n  tpl_name    VARCHAR(255) NOT NULL DEFAULT '',\n  parent_id   INT UNSIGNED NOT NULL DEFAULT 0,\n  action_id   INT UNSIGNED NOT NULL DEFAULT 0,\n  create_user VARCHAR(64)  NOT NULL DEFAULT '',\n  create_at   TIMESTAMP    NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  PRIMARY KEY (id),\n  UNIQUE KEY idx_tpl_name (tpl_name),\n  KEY idx_tpl_create_user (create_user)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\n\nDROP TABLE IF EXISTS strategy;\nCREATE TABLE `strategy` (\n  `id`          INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,\n  `metric`      VARCHAR(128)     NOT NULL DEFAULT '',\n  `tags`        VARCHAR(256)     NOT NULL DEFAULT '',\n  `max_step`    INT(11)          NOT NULL DEFAULT '1',\n  `priority`    TINYINT(4)       NOT NULL DEFAULT '0',\n  `func`        VARCHAR(16)      NOT NULL DEFAULT 'all(#1)',\n  `op`          VARCHAR(8)       NOT NULL DEFAULT '',\n  `right_value` VARCHAR(64)      NOT NULL,\n  `note`        VARCHAR(128)     NOT NULL DEFAULT '',\n  `run_begin`   VARCHAR(16)      NOT NULL DEFAULT '',\n  `run_end`     VARCHAR(16)      NOT NULL DEFAULT '',\n  `tpl_id`      INT(10) UNSIGNED NOT NULL DEFAULT '0',\n  PRIMARY KEY (`id`),\n  KEY `idx_strategy_tpl_id` (`tpl_id`)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\n\nDROP TABLE IF EXISTS expression;\nCREATE TABLE `expression` (\n  `id`          INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,\n  `expression`  VARCHAR(1024)    NOT NULL,\n  `func`        VARCHAR(16)      NOT NULL DEFAULT 'all(#1)',\n  `op`          VARCHAR(8)       NOT NULL DEFAULT '',\n  `right_value` VARCHAR(16)      NOT NULL DEFAULT '',\n  `max_step`    INT(11)          NOT NULL DEFAULT '1',\n  `priority`    TINYINT(4)       NOT NULL DEFAULT '0',\n  `note`        VARCHAR(1024)    NOT NULL DEFAULT '',\n  `action_id`   INT(10) UNSIGNED NOT NULL DEFAULT '0',\n  `create_user` VARCHAR(64)      NOT NULL DEFAULT '',\n  `pause`       TINYINT(1)       NOT NULL DEFAULT '0',\n  PRIMARY KEY (`id`)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\n\nDROP TABLE IF EXISTS grp_tpl;\nCREATE TABLE `grp_tpl` (\n  `grp_id`    INT(10) UNSIGNED NOT NULL,\n  `tpl_id`    INT(10) UNSIGNED NOT NULL,\n  `bind_user` VARCHAR(64)      NOT NULL DEFAULT '',\n  KEY `idx_grp_tpl_grp_id` (`grp_id`),\n  KEY `idx_grp_tpl_tpl_id` (`tpl_id`)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\nCREATE TABLE `plugin_dir` (\n  `id`          INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,\n  `grp_id`      INT(10) UNSIGNED NOT NULL,\n  `dir`         VARCHAR(255)     NOT NULL,\n  `create_user` VARCHAR(64)      NOT NULL DEFAULT '',\n  `create_at`   TIMESTAMP        NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`),\n  KEY `idx_plugin_dir_grp_id` (`grp_id`)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\n\nDROP TABLE IF EXISTS action;\nCREATE TABLE `action` (\n  `id`                   INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,\n  `uic`                  VARCHAR(255)     NOT NULL DEFAULT '',\n  `url`                  VARCHAR(255)     NOT NULL DEFAULT '',\n  `callback`             TINYINT(4)       NOT NULL DEFAULT '0',\n  `before_callback_sms`  TINYINT(4)       NOT NULL DEFAULT '0',\n  `before_callback_mail` TINYINT(4)       NOT NULL DEFAULT '0',\n  `after_callback_sms`   TINYINT(4)       NOT NULL DEFAULT '0',\n  `after_callback_mail`  TINYINT(4)       NOT NULL DEFAULT '0',\n  PRIMARY KEY (`id`)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\n/**\n * nodata mock config\n */\nDROP TABLE IF EXISTS `mockcfg`;\nCREATE TABLE `mockcfg` (\n  `id`       BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,\n  `name`     VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'name of mockcfg, used for uuid',\n  `obj`      VARCHAR(10240) NOT NULL DEFAULT '' COMMENT 'desc of object',\n  `obj_type` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'type of object, host or group or other',\n  `metric`   VARCHAR(128) NOT NULL DEFAULT '',\n  `tags`     VARCHAR(1024) NOT NULL DEFAULT '',\n  `dstype`   VARCHAR(32)  NOT NULL DEFAULT 'GAUGE',\n  `step`     INT(11) UNSIGNED  NOT NULL DEFAULT 60,\n  `mock`     DOUBLE  NOT NULL DEFAULT 0  COMMENT 'mocked value when nodata occurs',\n  `creator`  VARCHAR(64)  NOT NULL DEFAULT '',\n  `t_create` DATETIME NOT NULL COMMENT 'create time',\n  `t_modify` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'last modify time',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `uniq_name` (`name`)\n)\n  ENGINE=InnoDB\n  DEFAULT CHARSET=utf8\n  COLLATE=utf8_unicode_ci;\n\n/**\n *  aggregator cluster metric config table\n */\nDROP TABLE IF EXISTS `cluster`;\nCREATE TABLE `cluster` (\n  `id`          INT UNSIGNED   NOT NULL AUTO_INCREMENT,\n  `grp_id`      INT            NOT NULL,\n  `numerator`   VARCHAR(10240) NOT NULL,\n  `denominator` VARCHAR(10240) NOT NULL,\n  `endpoint`    VARCHAR(255)   NOT NULL,\n  `metric`      VARCHAR(255)   NOT NULL,\n  `tags`        VARCHAR(255)   NOT NULL,\n  `ds_type`     VARCHAR(255)   NOT NULL,\n  `step`        INT            NOT NULL,\n  `last_update` TIMESTAMP      NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  `creator`     VARCHAR(255)   NOT NULL,\n  PRIMARY KEY (`id`)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET=utf8\n  COLLATE=utf8_unicode_ci;\n\n/**\n * alert links\n */\nDROP TABLE IF EXISTS alert_link;\nCREATE TABLE alert_link\n(\n  id        INT UNSIGNED NOT NULL AUTO_INCREMENT,\n  path      VARCHAR(16)  NOT NULL DEFAULT '',\n  content   MEDIUMTEXT   NOT NULL,\n  create_at TIMESTAMP    NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  PRIMARY KEY (id),\n  UNIQUE KEY alert_path(path)\n)\n  ENGINE =InnoDB\n  DEFAULT CHARSET =utf8\n  COLLATE =utf8_unicode_ci;\n\n"
  },
  {
    "path": "scripts/mysql/db_schema/3_dashboard-db-schema.sql",
    "content": "-- MySQL dump 10.13  Distrib 5.5.31, for Linux (x86_64)\n--\n-- Host: 127.0.0.1    Database: dashboard\n-- ------------------------------------------------------\n-- Server version\t5.5.31-log\n\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\n/*!40101 SET NAMES utf8 */;\n/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n/*!40103 SET TIME_ZONE='+00:00' */;\n/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n\n--\n-- Table structure for table `dashboard_graph`\n--\n\nCREATE DATABASE dashboard\n  DEFAULT CHARACTER SET utf8\n  DEFAULT COLLATE utf8_general_ci;\nUSE dashboard;\nSET NAMES utf8;\n\nDROP TABLE IF EXISTS `dashboard_graph`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `dashboard_graph` (\n  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n  `title` char(128) NOT NULL,\n  `hosts` varchar(10240) NOT NULL DEFAULT '',\n  `counters` varchar(1024) NOT NULL DEFAULT '',\n  `screen_id` int(11) unsigned NOT NULL,\n  `timespan` int(11) unsigned NOT NULL DEFAULT '3600',\n  `graph_type` char(2) NOT NULL DEFAULT 'h',\n  `method` char(8) DEFAULT '',\n  `position` int(11) unsigned NOT NULL DEFAULT '0',\n  `falcon_tags` varchar(512) NOT NULL DEFAULT '',\n  PRIMARY KEY (`id`),\n  KEY `idx_sid` (`screen_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Table structure for table `dashboard_screen`\n--\n\nDROP TABLE IF EXISTS `dashboard_screen`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `dashboard_screen` (\n  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n  `pid` int(11) unsigned NOT NULL DEFAULT '0',\n  `name` char(128) NOT NULL,\n  `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`),\n  KEY `idx_pid` (`pid`),\n  UNIQUE KEY `idx_pid_n` (`pid`,`name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n/*!40101 SET character_set_client = @saved_cs_client */;\n\n--\n-- Table structure for table `tmp_graph`\n--\n\nDROP TABLE IF EXISTS `tmp_graph`;\n/*!40101 SET @saved_cs_client     = @@character_set_client */;\n/*!40101 SET character_set_client = utf8 */;\nCREATE TABLE `tmp_graph` (\n  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n  `endpoints` varchar(10240) NOT NULL DEFAULT '',\n  `counters` varchar(10240) NOT NULL DEFAULT '',\n  `ck` varchar(32) NOT NULL,\n  `time_` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `idx_ck` (`ck`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n/*!40101 SET character_set_client = @saved_cs_client */;\n/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n\n"
  },
  {
    "path": "scripts/mysql/db_schema/4_graph-db-schema.sql",
    "content": "CREATE DATABASE graph\n  DEFAULT CHARACTER SET utf8\n  DEFAULT COLLATE utf8_general_ci;\nUSE graph;\nSET NAMES utf8;\n\nDROP TABLE if exists `graph`.`endpoint`;\nCREATE TABLE `graph`.`endpoint` (\n  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `endpoint` varchar(255) NOT NULL DEFAULT '',\n  `ts` int(11) DEFAULT NULL,\n  `t_create` DATETIME NOT NULL COMMENT 'create time',\n  `t_modify` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'last modify time',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `idx_endpoint` (`endpoint`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nDROP TABLE if exists `graph`.`endpoint_counter`;\nCREATE TABLE `graph`.`endpoint_counter` (\n  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `endpoint_id` int(10) unsigned NOT NULL,\n  `counter` varchar(255) NOT NULL DEFAULT '',\n  `step` int(11) not null default 60 comment 'in second',\n  `type` varchar(16) not null comment 'GAUGE|COUNTER|DERIVE',\n  `ts` int(11) DEFAULT NULL,\n  `t_create` DATETIME NOT NULL COMMENT 'create time',\n  `t_modify` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'last modify time',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `idx_endpoint_id_counter` (`endpoint_id`, `counter`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nDROP TABLE if exists `graph`.`tag_endpoint`;\nCREATE TABLE `graph`.`tag_endpoint` (\n  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `tag` varchar(255) NOT NULL DEFAULT '' COMMENT 'srv=tv',\n  `endpoint_id` int(10) unsigned NOT NULL,\n  `ts` int(11) DEFAULT NULL,\n  `t_create` DATETIME NOT NULL COMMENT 'create time',\n  `t_modify` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'last modify time',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `idx_tag_endpoint_id` (`tag`, `endpoint_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n"
  },
  {
    "path": "scripts/mysql/db_schema/5_alarms-db-schema.sql",
    "content": "CREATE DATABASE alarms\n  DEFAULT CHARACTER SET utf8\n  DEFAULT COLLATE utf8_general_ci;\nUSE alarms;\nSET NAMES utf8;\n\n/*\n* 建立告警归档资料表, 主要存储各个告警的最后触发状况\n*/\nDROP TABLE IF EXISTS event_cases;\nCREATE TABLE IF NOT EXISTS event_cases(\n                id VARCHAR(50),\n                endpoint VARCHAR(100) NOT NULL,\n                metric VARCHAR(200) NOT NULL,\n                func VARCHAR(50),\n                cond VARCHAR(200) NOT NULL,\n                note VARCHAR(500),\n                max_step int(10) unsigned,\n                current_step int(10) unsigned,\n                priority INT(6) NOT NULL,\n                status VARCHAR(20) NOT NULL,\n                timestamp Timestamp NOT NULL,\n                update_at Timestamp NULL DEFAULT NULL,\n                closed_at Timestamp NULL DEFAULT NULL,\n                closed_note VARCHAR(250),\n                user_modified int(10) unsigned,\n                tpl_creator VARCHAR(64),\n                expression_id int(10) unsigned,\n                strategy_id int(10) unsigned,\n                template_id int(10) unsigned,\n                process_note MEDIUMINT,\n                process_status VARCHAR(20) DEFAULT 'unresolved',\n                PRIMARY KEY (id),\n                INDEX (endpoint, strategy_id, template_id)\n)\n        ENGINE =InnoDB\n        DEFAULT CHARSET =utf8;\n\n\n/*\n* 建立告警归档资料表, 存储各个告警触发状况的历史状态\n*/\nDROP TABLE IF EXISTS events;\nCREATE TABLE IF NOT EXISTS events (\n                id int(10) NOT NULL AUTO_INCREMENT,\n                event_caseId VARCHAR(50),\n                step int(10) unsigned,\n                cond VARCHAR(200) NOT NULL,\n                status int(3) unsigned DEFAULT 0,\n                timestamp Timestamp,\n                PRIMARY KEY (id),\n                INDEX(event_caseId),\n                FOREIGN KEY (event_caseId) REFERENCES event_cases(id)\n                        ON DELETE CASCADE\n                        ON UPDATE CASCADE\n)\n        ENGINE =InnoDB\n        DEFAULT CHARSET =utf8;\n\n/*\n* 告警留言表\n*/\nCREATE TABLE IF NOT EXISTS event_note (\n  id MEDIUMINT NOT NULL AUTO_INCREMENT,\n  event_caseId VARCHAR(50),\n  note    VARCHAR(300),\n  case_id VARCHAR(20),\n  status VARCHAR(15),\n  timestamp Timestamp,\n  user_id int(10) unsigned,\n  PRIMARY KEY (id),\n  INDEX (event_caseId),\n  FOREIGN KEY (event_caseId) REFERENCES event_cases(id)\n    ON DELETE CASCADE\n    ON UPDATE CASCADE,\n  FOREIGN KEY (user_id) REFERENCES uic.user(id)\n    ON DELETE CASCADE\n    ON UPDATE CASCADE\n);\n"
  },
  {
    "path": "test/README.md",
    "content": ""
  },
  {
    "path": "vagrant/Vagrantfile",
    "content": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\n  \nVagrant.configure(2) do |config|\n  config.vm.box = \"openfalcon-docker\"\n  config.vm.host_name = \"openfalcon-docker\"\n  \n  # Use default insecure key\n  config.ssh.insert_key = false\n  \n  # All configurations use 10.20.30.40 as entry.\n  config.vm.network \"private_network\", ip: \"10.20.30.40\"\n  \n  # MySQL needs at least 1024 MB\n  config.vm.provider \"virtualbox\" do |vb|\n    vb.memory = \"2048\"\n  end\n  \n  # Let timezone in guest be same as host\n  # Install timezone plugin:\n  #   $ vagrant plugin install vagrant-timezone\n  if Vagrant.has_plugin?(\"vagrant-timezone\")\n    config.timezone.value = \"Asia/Taipei\"\n  end\n  \n  # Auto snapshot when vagrant up first\n  # Install trigger and snapshot plugin:\n  #   $ vagrant plugin install vagrant-triggers\n  #   $ vagrant plugin install vagrant-vbox-snapshot\n  if Vagrant.has_plugin?(\"vagrant-triggers\") and Vagrant.has_plugin?(\"vagrant-vbox-snapshot\")\n    config.trigger.after :up do\n      `vagrant snapshot list \"#{@machine.name}\"`\n      unless $?.exitstatus == 0\n        `vagrant snapshot take \"#{@machine.name}\" baseline`\n        @machine.ui.info(\"Took initial snapshot\")\n      end\n    end\n    config.trigger.before :destroy do\n      `vagrant snapshot delete \"#{@machine.name}\" baseline`\n    end\n  end\nend\n"
  },
  {
    "path": "version.go",
    "content": "// Copyright 2017 Xiaomi, Inc.\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// build !release\npackage main\n\nvar (\n\tVersion    = \"<UNDEFINED>\"\n\tGitCommit  = \"<UNDEFINED>\"\n\tBinaryName = \"<UNDEFINED>\"\n)\n"
  }
]