From 2cf84b81ae980870e5b7a281b675428e03e233ce Mon Sep 17 00:00:00 2001 From: marvzhang Date: Fri, 4 Dec 2020 15:33:15 +0800 Subject: [PATCH 01/19] code cleanup --- backend/conf/config.yml | 6 +- backend/config/config.go | 57 - backend/config/config_test.go | 16 - backend/constants/action.go | 8 - backend/constants/anchor.go | 8 - backend/constants/auth.go | 7 - backend/constants/challenge.go | 20 - backend/constants/channels.go | 9 - backend/constants/common.go | 6 - backend/constants/config_spider.go | 6 - backend/constants/context.go | 5 - backend/constants/errors.go | 13 - backend/constants/log.go | 5 - backend/constants/message.go | 9 - backend/constants/model.go | 6 - backend/constants/node.go | 6 - backend/constants/notification.go | 13 - backend/constants/register.go | 8 - backend/constants/rpc.go | 12 - backend/constants/schedule.go | 10 - backend/constants/scrapy.go | 5 - backend/constants/spider.go | 7 - backend/constants/system.go | 25 - backend/constants/task.go | 32 - backend/constants/user.go | 6 - backend/constants/variable.go | 9 - backend/data/challenge_data.json | 142 - backend/database/es_base.go | 44 - backend/database/mongo.go | 112 - backend/database/mongo_test.go | 70 - backend/database/pubsub.go | 96 - backend/database/redis.go | 289 - backend/docs/docs.go | 4808 ----------------- backend/docs/swagger.json | 4740 ---------------- backend/docs/swagger.yaml | 3177 ----------- backend/dump.rdb | Bin 155 -> 0 bytes backend/entity/common.go | 17 - backend/entity/config_spider.go | 40 - backend/entity/doc.go | 8 - backend/entity/node.go | 28 - backend/entity/rpc.go | 11 - backend/entity/spider.go | 17 - backend/entity/system.go | 39 - backend/entity/version.go | 23 - backend/errors/errors.go | 54 - backend/go.mod | 48 +- backend/go.sum | 19 + backend/lib/cron/.gitignore | 22 - backend/lib/cron/.travis.yml | 1 - backend/lib/cron/LICENSE | 21 - backend/lib/cron/README.md | 125 - backend/lib/cron/chain.go | 92 - backend/lib/cron/chain_test.go | 221 - backend/lib/cron/constantdelay.go | 27 - backend/lib/cron/constantdelay_test.go | 54 - backend/lib/cron/cron.go | 350 -- backend/lib/cron/cron_test.go | 699 --- backend/lib/cron/doc.go | 212 - backend/lib/cron/logger.go | 86 - backend/lib/cron/option.go | 45 - backend/lib/cron/option_test.go | 42 - backend/lib/cron/parser.go | 434 -- backend/lib/cron/parser_test.go | 384 -- backend/lib/cron/spec.go | 188 - backend/lib/cron/spec_test.go | 300 - backend/lib/validate/mongo.go | 10 - backend/main.go | 66 +- backend/middlewares/auth.go | 48 - backend/middlewares/cors.go | 19 - backend/middlewares/es_log.go | 54 - backend/mock/base.go | 16 - backend/mock/file.go | 8 - backend/mock/node.go | 222 - backend/mock/node_test.go | 198 - backend/mock/schedule.go | 136 - backend/mock/schedule_test.go | 141 - backend/mock/spider.go | 187 - backend/mock/spider_test.go | 139 - backend/mock/stats.go | 62 - backend/mock/stats_test.go | 29 - backend/mock/system.go | 1 - backend/mock/task.go | 236 - backend/mock/task_test.go | 138 - backend/mock/user.go | 1 - backend/mock/utils.go | 24 - backend/model/action.go | 162 - backend/model/base.go | 12 - backend/model/challenge.go | 187 - backend/model/config_spider/common.go | 26 - backend/model/config_spider/scrapy.go | 263 - backend/model/file.go | 78 - backend/model/log.go | 167 - backend/model/market/repo.go | 4 - backend/model/node.go | 232 - backend/model/node_test.go | 50 - backend/model/project.go | 167 - backend/model/schedule.go | 177 - backend/model/setting.go | 45 - backend/model/spider.go | 414 -- backend/model/system.go | 98 - backend/model/task.go | 534 -- backend/model/token.go | 80 - backend/model/user.go | 166 - backend/model/variable.go | 97 - backend/routes/action.go | 118 - backend/routes/base.go | 24 - backend/routes/challenge.go | 45 - backend/routes/config_spider.go | 411 -- backend/routes/doc.go | 33 - backend/routes/file.go | 29 - backend/routes/git.go | 84 - backend/routes/market.go | 1 - backend/routes/node.go | 198 - backend/routes/project.go | 245 - backend/routes/repos.go | 81 - backend/routes/schedule.go | 323 -- backend/routes/setting.go | 55 - backend/routes/spider.go | 1910 ------- backend/routes/stats.go | 90 - backend/routes/system.go | 344 -- backend/routes/system_tasks.go | 118 - backend/routes/task.go | 621 --- backend/routes/token.go | 96 - backend/routes/user.go | 340 -- backend/routes/utils.go | 39 - backend/routes/variable.go | 111 - backend/routes/version.go | 30 - backend/scripts/install-chromedriver.sh | 31 - backend/scripts/install-dotnet.sh | 22 - backend/scripts/install-firefox.sh | 20 - backend/scripts/install-go.sh | 24 - backend/scripts/install-java.sh | 22 - backend/scripts/install-nodejs.sh | 46 - backend/scripts/install-nvm.sh | 428 -- backend/scripts/install-php.sh | 18 - backend/scripts/install-ruby.sh | 12 - backend/scripts/install.sh | 44 - backend/services/auth.go | 20 - backend/services/challenge/base.go | 138 - .../challenge/create_configurable_spider.go | 23 - .../challenge/create_customized_spider.go | 23 - backend/services/challenge/create_nodes.go | 22 - backend/services/challenge/create_schedule.go | 21 - backend/services/challenge/create_user.go | 21 - backend/services/challenge/install_dep.go | 23 - backend/services/challenge/install_lang.go | 23 - backend/services/challenge/login_180d.go | 18 - backend/services/challenge/login_30d.go | 18 - backend/services/challenge/login_7d.go | 18 - backend/services/challenge/login_90d.go | 18 - backend/services/challenge/run_random.go | 25 - backend/services/challenge/scrape_100k.go | 24 - backend/services/challenge/scrape_10k.go | 24 - backend/services/challenge/scrape_1k.go | 24 - backend/services/challenge/view_disclaimer.go | 23 - backend/services/clean.go | 122 - backend/services/config_spider.go | 278 - backend/services/context/context.go | 99 - backend/services/doc.go | 27 - backend/services/file.go | 65 - backend/services/git.go | 603 --- backend/services/local_node/local_node.go | 25 - backend/services/local_node/mongo_info.go | 62 - backend/services/local_node/node_info.go | 74 - backend/services/log.go | 188 - backend/services/log_test.go | 41 - backend/services/msg_handler/handler.go | 37 - backend/services/msg_handler/msg_log.go | 54 - backend/services/msg_handler/msg_spider.go | 24 - .../services/msg_handler/msg_system_info.go | 29 - backend/services/msg_handler/msg_task.go | 40 - backend/services/node.go | 255 - backend/services/notification/mail.go | 138 - backend/services/notification/mobile.go | 59 - backend/services/repo.go | 93 - backend/services/rpc/base.go | 146 - backend/services/rpc/cancel_task.go | 63 - backend/services/rpc/get_installed_deps.go | 123 - backend/services/rpc/get_lang.go | 82 - backend/services/rpc/get_system_info.go | 67 - backend/services/rpc/install_dep.go | 100 - backend/services/rpc/install_lang.go | 73 - backend/services/rpc/remove_spider.go | 62 - backend/services/rpc/uninstall_dep.go | 96 - backend/services/schedule.go | 274 - backend/services/scrapy.go | 285 - backend/services/spider.go | 624 --- backend/services/spider_handler/spider.go | 250 - .../services/spider_handler/spider_test.go | 53 - backend/services/sys_exec/linux_mac.go | 30 - backend/services/sys_exec/windows.go | 24 - backend/services/system.go | 393 -- backend/services/task.go | 1051 ---- backend/services/user.go | 133 - backend/services/version.go | 29 - .../template/scrapy/config_spider/__init__.py | 0 .../template/scrapy/config_spider/items.py | 12 - .../scrapy/config_spider/middlewares.py | 103 - .../scrapy/config_spider/pipelines.py | 27 - .../template/scrapy/config_spider/settings.py | 111 - .../scrapy/config_spider/spiders/__init__.py | 4 - .../scrapy/config_spider/spiders/spider.py | 21 - backend/template/scrapy/scrapy.cfg | 11 - .../template/spiderfile/Spiderfile.163_news | 19 - backend/template/spiderfile/Spiderfile.baidu | 21 - .../spiderfile/Spiderfile.toscrapy_books | 27 - .../template/spiders/amazon_config/Spiderfile | 51 - .../spiders/autohome_config/Spiderfile | 57 - .../template/spiders/baidu_config/Spiderfile | 39 - .../template/spiders/bing_general/Spiderfile | 6 - .../spiders/bing_general/bing_spider.py | 41 - backend/template/spiders/chinaz/Spiderfile | 5 - .../spiders/chinaz/chinaz/__init__.py | 0 .../template/spiders/chinaz/chinaz/items.py | 21 - .../spiders/chinaz/chinaz/middlewares.py | 103 - .../spiders/chinaz/chinaz/pipelines.py | 7 - .../spiders/chinaz/chinaz/settings.py | 90 - .../spiders/chinaz/chinaz/spiders/__init__.py | 4 - .../chinaz/chinaz/spiders/chinaz_spider.py | 63 - backend/template/spiders/chinaz/scrapy.cfg | 11 - backend/template/spiders/csdn/csdn_spider.js | 87 - .../template/spiders/csdn_config/Spiderfile | 60 - .../template/spiders/douban_config/Spiderfile | 57 - backend/template/spiders/jd/Spiderfile | 5 - backend/template/spiders/jd/jd/__init__.py | 0 backend/template/spiders/jd/jd/items.py | 15 - backend/template/spiders/jd/jd/middlewares.py | 103 - backend/template/spiders/jd/jd/pipelines.py | 6 - backend/template/spiders/jd/jd/settings.py | 90 - .../spiders/jd/jd/spiders/__init__.py | 4 - .../spiders/jd/jd/spiders/jd_spider.py | 21 - backend/template/spiders/jd/scrapy.cfg | 11 - backend/template/spiders/jd_mask/Spiderfile | 5 - .../spiders/jd_mask/jd_mask_spider.js | 84 - .../spiders/juejin_node/juejin_spider.js | 84 - .../template/spiders/realestate/Spiderfile | 4 - .../spiders/realestate/realestate/__init__.py | 0 .../spiders/realestate/realestate/items.py | 37 - .../realestate/realestate/middlewares.py | 103 - .../realestate/realestate/pipelines.py | 6 - .../spiders/realestate/realestate/settings.py | 89 - .../realestate/realestate/spiders/__init__.py | 4 - .../realestate/realestate/spiders/lianjia.py | 31 - .../template/spiders/realestate/scrapy.cfg | 11 - .../segmentfault/segmentfault_spider.js | 81 - .../spiders/segmentfault_colly/.crawlabignore | 2 - .../spiders/segmentfault_colly/go.mod | 9 - .../spiders/segmentfault_colly/go.sum | 454 -- .../spiders/segmentfault_colly/main.go | 43 - backend/template/spiders/sinastock/Spiderfile | 5 - backend/template/spiders/sinastock/scrapy.cfg | 11 - .../spiders/sinastock/sinastock/__init__.py | 0 .../spiders/sinastock/sinastock/items.py | 21 - .../sinastock/sinastock/middlewares.py | 103 - .../spiders/sinastock/sinastock/pipelines.py | 6 - .../spiders/sinastock/sinastock/settings.py | 89 - .../sinastock/sinastock/spiders/__init__.py | 4 - .../sinastock/spiders/sinastock_spider.py | 53 - .../sites_inspector/sites_inspector.py | 77 - .../template/spiders/v2ex_config/Spiderfile | 54 - backend/template/spiders/xueqiu/Spiderfile | 5 - backend/template/spiders/xueqiu/scrapy.cfg | 11 - .../spiders/xueqiu/xueqiu/__init__.py | 0 .../template/spiders/xueqiu/xueqiu/items.py | 23 - .../spiders/xueqiu/xueqiu/middlewares.py | 103 - .../spiders/xueqiu/xueqiu/pipelines.py | 6 - .../spiders/xueqiu/xueqiu/settings.py | 89 - .../spiders/xueqiu/xueqiu/spiders/__init__.py | 4 - .../xueqiu/xueqiu/spiders/xueqiu_spider.py | 46 - .../template/spiders/xueqiu_config/Spiderfile | 39 - .../spiders/zongheng_config/Spiderfile | 45 - backend/test/test.http | 49 - backend/utils/array.go | 10 - backend/utils/chan.go | 40 - backend/utils/chan_test.go | 78 - backend/utils/encrypt.go | 16 - backend/utils/file.go | 385 -- backend/utils/file_test.go | 129 - backend/utils/helpers.go | 60 - backend/utils/model.go | 24 - backend/utils/model_test.go | 49 - backend/utils/rpc.go | 14 - backend/utils/spider.go | 8 - backend/utils/system.go | 149 - backend/utils/time.go | 16 - backend/utils/user.go | 14 - backend/utils/user_test.go | 14 - 287 files changed, 63 insertions(+), 39029 deletions(-) delete mode 100644 backend/config/config.go delete mode 100644 backend/config/config_test.go delete mode 100644 backend/constants/action.go delete mode 100644 backend/constants/anchor.go delete mode 100644 backend/constants/auth.go delete mode 100644 backend/constants/challenge.go delete mode 100644 backend/constants/channels.go delete mode 100644 backend/constants/common.go delete mode 100644 backend/constants/config_spider.go delete mode 100644 backend/constants/context.go delete mode 100644 backend/constants/errors.go delete mode 100644 backend/constants/log.go delete mode 100644 backend/constants/message.go delete mode 100644 backend/constants/model.go delete mode 100644 backend/constants/node.go delete mode 100644 backend/constants/notification.go delete mode 100644 backend/constants/register.go delete mode 100644 backend/constants/rpc.go delete mode 100644 backend/constants/schedule.go delete mode 100644 backend/constants/scrapy.go delete mode 100644 backend/constants/spider.go delete mode 100644 backend/constants/system.go delete mode 100644 backend/constants/task.go delete mode 100644 backend/constants/user.go delete mode 100644 backend/constants/variable.go delete mode 100644 backend/data/challenge_data.json delete mode 100644 backend/database/es_base.go delete mode 100644 backend/database/mongo.go delete mode 100644 backend/database/mongo_test.go delete mode 100644 backend/database/pubsub.go delete mode 100644 backend/database/redis.go delete mode 100644 backend/docs/docs.go delete mode 100644 backend/docs/swagger.json delete mode 100644 backend/docs/swagger.yaml delete mode 100644 backend/dump.rdb delete mode 100644 backend/entity/common.go delete mode 100644 backend/entity/config_spider.go delete mode 100644 backend/entity/doc.go delete mode 100644 backend/entity/node.go delete mode 100644 backend/entity/rpc.go delete mode 100644 backend/entity/spider.go delete mode 100644 backend/entity/system.go delete mode 100644 backend/entity/version.go delete mode 100644 backend/errors/errors.go delete mode 100644 backend/lib/cron/.gitignore delete mode 100644 backend/lib/cron/.travis.yml delete mode 100644 backend/lib/cron/LICENSE delete mode 100644 backend/lib/cron/README.md delete mode 100644 backend/lib/cron/chain.go delete mode 100644 backend/lib/cron/chain_test.go delete mode 100644 backend/lib/cron/constantdelay.go delete mode 100644 backend/lib/cron/constantdelay_test.go delete mode 100644 backend/lib/cron/cron.go delete mode 100644 backend/lib/cron/cron_test.go delete mode 100644 backend/lib/cron/doc.go delete mode 100644 backend/lib/cron/logger.go delete mode 100644 backend/lib/cron/option.go delete mode 100644 backend/lib/cron/option_test.go delete mode 100644 backend/lib/cron/parser.go delete mode 100644 backend/lib/cron/parser_test.go delete mode 100644 backend/lib/cron/spec.go delete mode 100644 backend/lib/cron/spec_test.go delete mode 100644 backend/lib/validate/mongo.go delete mode 100644 backend/middlewares/auth.go delete mode 100644 backend/middlewares/cors.go delete mode 100644 backend/middlewares/es_log.go delete mode 100644 backend/mock/base.go delete mode 100644 backend/mock/file.go delete mode 100644 backend/mock/node.go delete mode 100644 backend/mock/node_test.go delete mode 100644 backend/mock/schedule.go delete mode 100644 backend/mock/schedule_test.go delete mode 100644 backend/mock/spider.go delete mode 100644 backend/mock/spider_test.go delete mode 100644 backend/mock/stats.go delete mode 100644 backend/mock/stats_test.go delete mode 100644 backend/mock/system.go delete mode 100644 backend/mock/task.go delete mode 100644 backend/mock/task_test.go delete mode 100644 backend/mock/user.go delete mode 100644 backend/mock/utils.go delete mode 100644 backend/model/action.go delete mode 100644 backend/model/base.go delete mode 100644 backend/model/challenge.go delete mode 100644 backend/model/config_spider/common.go delete mode 100644 backend/model/config_spider/scrapy.go delete mode 100644 backend/model/file.go delete mode 100644 backend/model/log.go delete mode 100644 backend/model/market/repo.go delete mode 100644 backend/model/node.go delete mode 100644 backend/model/node_test.go delete mode 100644 backend/model/project.go delete mode 100644 backend/model/schedule.go delete mode 100644 backend/model/setting.go delete mode 100644 backend/model/spider.go delete mode 100644 backend/model/system.go delete mode 100644 backend/model/task.go delete mode 100644 backend/model/token.go delete mode 100644 backend/model/user.go delete mode 100644 backend/model/variable.go delete mode 100644 backend/routes/action.go delete mode 100644 backend/routes/base.go delete mode 100644 backend/routes/challenge.go delete mode 100644 backend/routes/config_spider.go delete mode 100644 backend/routes/doc.go delete mode 100644 backend/routes/file.go delete mode 100644 backend/routes/git.go delete mode 100644 backend/routes/market.go delete mode 100644 backend/routes/node.go delete mode 100644 backend/routes/project.go delete mode 100644 backend/routes/repos.go delete mode 100644 backend/routes/schedule.go delete mode 100644 backend/routes/setting.go delete mode 100644 backend/routes/spider.go delete mode 100644 backend/routes/stats.go delete mode 100644 backend/routes/system.go delete mode 100644 backend/routes/system_tasks.go delete mode 100644 backend/routes/task.go delete mode 100644 backend/routes/token.go delete mode 100644 backend/routes/user.go delete mode 100644 backend/routes/utils.go delete mode 100644 backend/routes/variable.go delete mode 100644 backend/routes/version.go delete mode 100644 backend/scripts/install-chromedriver.sh delete mode 100755 backend/scripts/install-dotnet.sh delete mode 100644 backend/scripts/install-firefox.sh delete mode 100644 backend/scripts/install-go.sh delete mode 100755 backend/scripts/install-java.sh delete mode 100644 backend/scripts/install-nodejs.sh delete mode 100755 backend/scripts/install-nvm.sh delete mode 100755 backend/scripts/install-php.sh delete mode 100755 backend/scripts/install-ruby.sh delete mode 100644 backend/scripts/install.sh delete mode 100644 backend/services/auth.go delete mode 100644 backend/services/challenge/base.go delete mode 100644 backend/services/challenge/create_configurable_spider.go delete mode 100644 backend/services/challenge/create_customized_spider.go delete mode 100644 backend/services/challenge/create_nodes.go delete mode 100644 backend/services/challenge/create_schedule.go delete mode 100644 backend/services/challenge/create_user.go delete mode 100644 backend/services/challenge/install_dep.go delete mode 100644 backend/services/challenge/install_lang.go delete mode 100644 backend/services/challenge/login_180d.go delete mode 100644 backend/services/challenge/login_30d.go delete mode 100644 backend/services/challenge/login_7d.go delete mode 100644 backend/services/challenge/login_90d.go delete mode 100644 backend/services/challenge/run_random.go delete mode 100644 backend/services/challenge/scrape_100k.go delete mode 100644 backend/services/challenge/scrape_10k.go delete mode 100644 backend/services/challenge/scrape_1k.go delete mode 100644 backend/services/challenge/view_disclaimer.go delete mode 100644 backend/services/clean.go delete mode 100644 backend/services/config_spider.go delete mode 100644 backend/services/context/context.go delete mode 100644 backend/services/doc.go delete mode 100644 backend/services/file.go delete mode 100644 backend/services/git.go delete mode 100644 backend/services/local_node/local_node.go delete mode 100644 backend/services/local_node/mongo_info.go delete mode 100644 backend/services/local_node/node_info.go delete mode 100644 backend/services/log.go delete mode 100644 backend/services/log_test.go delete mode 100644 backend/services/msg_handler/handler.go delete mode 100644 backend/services/msg_handler/msg_log.go delete mode 100644 backend/services/msg_handler/msg_spider.go delete mode 100644 backend/services/msg_handler/msg_system_info.go delete mode 100644 backend/services/msg_handler/msg_task.go delete mode 100644 backend/services/node.go delete mode 100644 backend/services/notification/mail.go delete mode 100644 backend/services/notification/mobile.go delete mode 100644 backend/services/repo.go delete mode 100644 backend/services/rpc/base.go delete mode 100644 backend/services/rpc/cancel_task.go delete mode 100644 backend/services/rpc/get_installed_deps.go delete mode 100644 backend/services/rpc/get_lang.go delete mode 100644 backend/services/rpc/get_system_info.go delete mode 100644 backend/services/rpc/install_dep.go delete mode 100644 backend/services/rpc/install_lang.go delete mode 100644 backend/services/rpc/remove_spider.go delete mode 100644 backend/services/rpc/uninstall_dep.go delete mode 100644 backend/services/schedule.go delete mode 100644 backend/services/scrapy.go delete mode 100644 backend/services/spider.go delete mode 100644 backend/services/spider_handler/spider.go delete mode 100644 backend/services/spider_handler/spider_test.go delete mode 100644 backend/services/sys_exec/linux_mac.go delete mode 100644 backend/services/sys_exec/windows.go delete mode 100644 backend/services/system.go delete mode 100644 backend/services/task.go delete mode 100644 backend/services/user.go delete mode 100644 backend/services/version.go delete mode 100644 backend/template/scrapy/config_spider/__init__.py delete mode 100644 backend/template/scrapy/config_spider/items.py delete mode 100644 backend/template/scrapy/config_spider/middlewares.py delete mode 100644 backend/template/scrapy/config_spider/pipelines.py delete mode 100644 backend/template/scrapy/config_spider/settings.py delete mode 100644 backend/template/scrapy/config_spider/spiders/__init__.py delete mode 100644 backend/template/scrapy/config_spider/spiders/spider.py delete mode 100644 backend/template/scrapy/scrapy.cfg delete mode 100644 backend/template/spiderfile/Spiderfile.163_news delete mode 100644 backend/template/spiderfile/Spiderfile.baidu delete mode 100644 backend/template/spiderfile/Spiderfile.toscrapy_books delete mode 100644 backend/template/spiders/amazon_config/Spiderfile delete mode 100644 backend/template/spiders/autohome_config/Spiderfile delete mode 100644 backend/template/spiders/baidu_config/Spiderfile delete mode 100644 backend/template/spiders/bing_general/Spiderfile delete mode 100644 backend/template/spiders/bing_general/bing_spider.py delete mode 100644 backend/template/spiders/chinaz/Spiderfile delete mode 100644 backend/template/spiders/chinaz/chinaz/__init__.py delete mode 100644 backend/template/spiders/chinaz/chinaz/items.py delete mode 100644 backend/template/spiders/chinaz/chinaz/middlewares.py delete mode 100644 backend/template/spiders/chinaz/chinaz/pipelines.py delete mode 100644 backend/template/spiders/chinaz/chinaz/settings.py delete mode 100644 backend/template/spiders/chinaz/chinaz/spiders/__init__.py delete mode 100644 backend/template/spiders/chinaz/chinaz/spiders/chinaz_spider.py delete mode 100644 backend/template/spiders/chinaz/scrapy.cfg delete mode 100644 backend/template/spiders/csdn/csdn_spider.js delete mode 100644 backend/template/spiders/csdn_config/Spiderfile delete mode 100644 backend/template/spiders/douban_config/Spiderfile delete mode 100644 backend/template/spiders/jd/Spiderfile delete mode 100644 backend/template/spiders/jd/jd/__init__.py delete mode 100644 backend/template/spiders/jd/jd/items.py delete mode 100644 backend/template/spiders/jd/jd/middlewares.py delete mode 100644 backend/template/spiders/jd/jd/pipelines.py delete mode 100644 backend/template/spiders/jd/jd/settings.py delete mode 100644 backend/template/spiders/jd/jd/spiders/__init__.py delete mode 100644 backend/template/spiders/jd/jd/spiders/jd_spider.py delete mode 100644 backend/template/spiders/jd/scrapy.cfg delete mode 100644 backend/template/spiders/jd_mask/Spiderfile delete mode 100644 backend/template/spiders/jd_mask/jd_mask_spider.js delete mode 100644 backend/template/spiders/juejin_node/juejin_spider.js delete mode 100644 backend/template/spiders/realestate/Spiderfile delete mode 100644 backend/template/spiders/realestate/realestate/__init__.py delete mode 100644 backend/template/spiders/realestate/realestate/items.py delete mode 100644 backend/template/spiders/realestate/realestate/middlewares.py delete mode 100644 backend/template/spiders/realestate/realestate/pipelines.py delete mode 100644 backend/template/spiders/realestate/realestate/settings.py delete mode 100644 backend/template/spiders/realestate/realestate/spiders/__init__.py delete mode 100644 backend/template/spiders/realestate/realestate/spiders/lianjia.py delete mode 100644 backend/template/spiders/realestate/scrapy.cfg delete mode 100644 backend/template/spiders/segmentfault/segmentfault_spider.js delete mode 100644 backend/template/spiders/segmentfault_colly/.crawlabignore delete mode 100644 backend/template/spiders/segmentfault_colly/go.mod delete mode 100644 backend/template/spiders/segmentfault_colly/go.sum delete mode 100644 backend/template/spiders/segmentfault_colly/main.go delete mode 100644 backend/template/spiders/sinastock/Spiderfile delete mode 100644 backend/template/spiders/sinastock/scrapy.cfg delete mode 100644 backend/template/spiders/sinastock/sinastock/__init__.py delete mode 100644 backend/template/spiders/sinastock/sinastock/items.py delete mode 100644 backend/template/spiders/sinastock/sinastock/middlewares.py delete mode 100644 backend/template/spiders/sinastock/sinastock/pipelines.py delete mode 100644 backend/template/spiders/sinastock/sinastock/settings.py delete mode 100644 backend/template/spiders/sinastock/sinastock/spiders/__init__.py delete mode 100644 backend/template/spiders/sinastock/sinastock/spiders/sinastock_spider.py delete mode 100644 backend/template/spiders/sites_inspector/sites_inspector.py delete mode 100644 backend/template/spiders/v2ex_config/Spiderfile delete mode 100644 backend/template/spiders/xueqiu/Spiderfile delete mode 100644 backend/template/spiders/xueqiu/scrapy.cfg delete mode 100644 backend/template/spiders/xueqiu/xueqiu/__init__.py delete mode 100644 backend/template/spiders/xueqiu/xueqiu/items.py delete mode 100644 backend/template/spiders/xueqiu/xueqiu/middlewares.py delete mode 100644 backend/template/spiders/xueqiu/xueqiu/pipelines.py delete mode 100644 backend/template/spiders/xueqiu/xueqiu/settings.py delete mode 100644 backend/template/spiders/xueqiu/xueqiu/spiders/__init__.py delete mode 100644 backend/template/spiders/xueqiu/xueqiu/spiders/xueqiu_spider.py delete mode 100644 backend/template/spiders/xueqiu_config/Spiderfile delete mode 100644 backend/template/spiders/zongheng_config/Spiderfile delete mode 100644 backend/test/test.http delete mode 100644 backend/utils/array.go delete mode 100644 backend/utils/chan.go delete mode 100644 backend/utils/chan_test.go delete mode 100644 backend/utils/encrypt.go delete mode 100644 backend/utils/file.go delete mode 100644 backend/utils/file_test.go delete mode 100644 backend/utils/helpers.go delete mode 100644 backend/utils/model.go delete mode 100644 backend/utils/model_test.go delete mode 100644 backend/utils/rpc.go delete mode 100644 backend/utils/spider.go delete mode 100644 backend/utils/system.go delete mode 100644 backend/utils/time.go delete mode 100644 backend/utils/user.go delete mode 100644 backend/utils/user_test.go diff --git a/backend/conf/config.yml b/backend/conf/config.yml index bc06935b..d3dc39a3 100644 --- a/backend/conf/config.yml +++ b/backend/conf/config.yml @@ -60,8 +60,4 @@ notification: senderIdentity: '' smtp: user: '' - password: '' -repo: - apiUrl: "https://center.crawlab.cn/api" -# apiUrl: "http://localhost:8002" - ossUrl: "https://repo.crawlab.cn" \ No newline at end of file + password: '' \ No newline at end of file diff --git a/backend/config/config.go b/backend/config/config.go deleted file mode 100644 index 79be808e..00000000 --- a/backend/config/config.go +++ /dev/null @@ -1,57 +0,0 @@ -package config - -import ( - "github.com/fsnotify/fsnotify" - "github.com/spf13/viper" - "log" - "strings" -) - -type Config struct { - Name string -} - -// 监控配置文件变化并热加载程序 -func (c *Config) WatchConfig() { - viper.WatchConfig() - viper.OnConfigChange(func(e fsnotify.Event) { - log.Printf("Config file changed: %s", e.Name) - }) -} - -func (c *Config) Init() error { - if c.Name != "" { - viper.SetConfigFile(c.Name) // 如果指定了配置文件,则解析指定的配置文件 - } else { - viper.AddConfigPath("./conf") // 如果没有指定配置文件,则解析默认的配置文件 - viper.SetConfigName("config") - } - viper.SetConfigType("yaml") // 设置配置文件格式为YAML - viper.AutomaticEnv() // 读取匹配的环境变量 - viper.SetEnvPrefix("CRAWLAB") // 读取环境变量的前缀为CRAWLAB - replacer := strings.NewReplacer(".", "_") - viper.SetEnvKeyReplacer(replacer) - if err := viper.ReadInConfig(); err != nil { // viper解析配置文件 - return err - } - - return nil -} - -func InitConfig(cfg string) error { - c := Config{ - Name: cfg, - } - - // 初始化配置文件 - if err := c.Init(); err != nil { - return err - } - - // 监控配置文件变化并热加载程序 - c.WatchConfig() - - return nil -} - - diff --git a/backend/config/config_test.go b/backend/config/config_test.go deleted file mode 100644 index 0068e6ad..00000000 --- a/backend/config/config_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package config - -import ( - . "github.com/smartystreets/goconvey/convey" - "testing" -) - -func TestInitConfig(t *testing.T) { - Convey("Test InitConfig func", t, func() { - x := InitConfig("../conf/config.yml") - - Convey("The value should be nil", func() { - So(x, ShouldEqual, nil) - }) - }) -} diff --git a/backend/constants/action.go b/backend/constants/action.go deleted file mode 100644 index 389a11bc..00000000 --- a/backend/constants/action.go +++ /dev/null @@ -1,8 +0,0 @@ -package constants - -const ( - ActionTypeVisit = "visit" - ActionTypeInstallDep = "install_dep" - ActionTypeInstallLang = "install_lang" - ActionTypeViewDisclaimer = "view_disclaimer" -) diff --git a/backend/constants/anchor.go b/backend/constants/anchor.go deleted file mode 100644 index f462135f..00000000 --- a/backend/constants/anchor.go +++ /dev/null @@ -1,8 +0,0 @@ -package constants - -const ( - AnchorStartStage = "START_STAGE" - AnchorStartUrl = "START_URL" - AnchorItems = "ITEMS" - AnchorParsers = "PARSERS" -) diff --git a/backend/constants/auth.go b/backend/constants/auth.go deleted file mode 100644 index 136391a0..00000000 --- a/backend/constants/auth.go +++ /dev/null @@ -1,7 +0,0 @@ -package constants - -const ( - OwnerTypeAll = "all" - OwnerTypeMe = "me" - OwnerTypePublic = "public" -) diff --git a/backend/constants/challenge.go b/backend/constants/challenge.go deleted file mode 100644 index 5c056e91..00000000 --- a/backend/constants/challenge.go +++ /dev/null @@ -1,20 +0,0 @@ -package constants - -const ( - ChallengeLogin7d = "login_7d" - ChallengeLogin30d = "login_30d" - ChallengeLogin90d = "login_90d" - ChallengeLogin180d = "login_180d" - ChallengeCreateCustomizedSpider = "create_customized_spider" - ChallengeCreateConfigurableSpider = "create_configurable_spider" - ChallengeCreateSchedule = "create_schedule" - ChallengeCreateNodes = "create_nodes" - ChallengeCreateUser = "create_user" - ChallengeRunRandom = "run_random" - ChallengeScrape1k = "scrape_1k" - ChallengeScrape10k = "scrape_10k" - ChallengeScrape100k = "scrape_100k" - ChallengeInstallDep = "install_dep" - ChallengeInstallLang = "install_lang" - ChallengeViewDisclaimer = "view_disclaimer" -) diff --git a/backend/constants/channels.go b/backend/constants/channels.go deleted file mode 100644 index c38a5ac9..00000000 --- a/backend/constants/channels.go +++ /dev/null @@ -1,9 +0,0 @@ -package constants - -const ( - ChannelAllNode = "nodes:public" - - ChannelWorkerNode = "nodes:" - - ChannelMasterNode = "nodes:master" -) diff --git a/backend/constants/common.go b/backend/constants/common.go deleted file mode 100644 index 9ac6cdbc..00000000 --- a/backend/constants/common.go +++ /dev/null @@ -1,6 +0,0 @@ -package constants - -const ( - ASCENDING = "ascending" - DESCENDING = "descending" -) diff --git a/backend/constants/config_spider.go b/backend/constants/config_spider.go deleted file mode 100644 index c29624dc..00000000 --- a/backend/constants/config_spider.go +++ /dev/null @@ -1,6 +0,0 @@ -package constants - -const ( - EngineScrapy = "scrapy" - EngineColly = "colly" -) diff --git a/backend/constants/context.go b/backend/constants/context.go deleted file mode 100644 index 0759b54b..00000000 --- a/backend/constants/context.go +++ /dev/null @@ -1,5 +0,0 @@ -package constants - -const ( - ContextUser = "currentUser" -) diff --git a/backend/constants/errors.go b/backend/constants/errors.go deleted file mode 100644 index a273cb75..00000000 --- a/backend/constants/errors.go +++ /dev/null @@ -1,13 +0,0 @@ -package constants - -import ( - "crawlab/errors" - "net/http" -) - -var ( - ErrorMongoError = errors.NewSystemOPError(1001, "system error:[mongo]%s", http.StatusInternalServerError) - //users - ErrorUserNotFound = errors.NewBusinessError(10001, "user not found.", http.StatusUnauthorized) - ErrorUsernameOrPasswordInvalid = errors.NewBusinessError(11001, "username or password invalid", http.StatusUnauthorized) -) diff --git a/backend/constants/log.go b/backend/constants/log.go deleted file mode 100644 index 5f0b4a66..00000000 --- a/backend/constants/log.go +++ /dev/null @@ -1,5 +0,0 @@ -package constants - -const ( - ErrorRegexPattern = "(?:[ :,.]|^)((?:error|exception|traceback)s?)(?:[ :,.]|$)" -) diff --git a/backend/constants/message.go b/backend/constants/message.go deleted file mode 100644 index 72e5fab2..00000000 --- a/backend/constants/message.go +++ /dev/null @@ -1,9 +0,0 @@ -package constants - -const ( - MsgTypeGetLog = "get-log" - MsgTypeGetSystemInfo = "get-sys-info" - MsgTypeCancelTask = "cancel-task" - MsgTypeRemoveLog = "remove-log" - MsgTypeRemoveSpider = "remove-spider" -) diff --git a/backend/constants/model.go b/backend/constants/model.go deleted file mode 100644 index da66b15f..00000000 --- a/backend/constants/model.go +++ /dev/null @@ -1,6 +0,0 @@ -package constants - -const ( - ObjectIdNull = "000000000000000000000000" - Infinite = 999999999 -) diff --git a/backend/constants/node.go b/backend/constants/node.go deleted file mode 100644 index 29b0b7c1..00000000 --- a/backend/constants/node.go +++ /dev/null @@ -1,6 +0,0 @@ -package constants - -const ( - StatusOnline = "online" - StatusOffline = "offline" -) diff --git a/backend/constants/notification.go b/backend/constants/notification.go deleted file mode 100644 index cf3da062..00000000 --- a/backend/constants/notification.go +++ /dev/null @@ -1,13 +0,0 @@ -package constants - -const ( - NotificationTriggerOnTaskEnd = "notification_trigger_on_task_end" - NotificationTriggerOnTaskError = "notification_trigger_on_task_error" - NotificationTriggerNever = "notification_trigger_never" -) - -const ( - NotificationTypeMail = "notification_type_mail" - NotificationTypeDingTalk = "notification_type_ding_talk" - NotificationTypeWechat = "notification_type_wechat" -) diff --git a/backend/constants/register.go b/backend/constants/register.go deleted file mode 100644 index 4ed1e396..00000000 --- a/backend/constants/register.go +++ /dev/null @@ -1,8 +0,0 @@ -package constants - -const ( - RegisterTypeMac = "mac" - RegisterTypeIp = "ip" - RegisterTypeHostname = "hostname" - RegisterTypeCustomName = "customName" -) diff --git a/backend/constants/rpc.go b/backend/constants/rpc.go deleted file mode 100644 index 0fd7ad9f..00000000 --- a/backend/constants/rpc.go +++ /dev/null @@ -1,12 +0,0 @@ -package constants - -const ( - RpcInstallLang = "install_lang" - RpcInstallDep = "install_dep" - RpcUninstallDep = "uninstall_dep" - RpcGetInstalledDepList = "get_installed_dep_list" - RpcGetLang = "get_lang" - RpcCancelTask = "cancel_task" - RpcGetSystemInfoService = "get_system_info" - RpcRemoveSpider = "remove_spider" -) diff --git a/backend/constants/schedule.go b/backend/constants/schedule.go deleted file mode 100644 index 520626a9..00000000 --- a/backend/constants/schedule.go +++ /dev/null @@ -1,10 +0,0 @@ -package constants - -const ( - ScheduleStatusStop = "stopped" - ScheduleStatusRunning = "running" - ScheduleStatusError = "error" - - ScheduleStatusErrorNotFoundNode = "Not Found Node" - ScheduleStatusErrorNotFoundSpider = "Not Found Spider" -) diff --git a/backend/constants/scrapy.go b/backend/constants/scrapy.go deleted file mode 100644 index bc82508f..00000000 --- a/backend/constants/scrapy.go +++ /dev/null @@ -1,5 +0,0 @@ -package constants - -const ScrapyProtectedStageNames = "" - -const ScrapyProtectedFieldNames = "_id,task_id,ts" diff --git a/backend/constants/spider.go b/backend/constants/spider.go deleted file mode 100644 index 5119aa67..00000000 --- a/backend/constants/spider.go +++ /dev/null @@ -1,7 +0,0 @@ -package constants - -const ( - Customized = "customized" - Configurable = "configurable" - Plugin = "plugin" -) diff --git a/backend/constants/system.go b/backend/constants/system.go deleted file mode 100644 index 14c45698..00000000 --- a/backend/constants/system.go +++ /dev/null @@ -1,25 +0,0 @@ -package constants - -const ( - Windows = "windows" - Linux = "linux" - Darwin = "darwin" -) - -const ( - Python = "python" - Nodejs = "node" - Java = "java" -) - -const ( - InstallStatusNotInstalled = "not-installed" - InstallStatusInstalling = "installing" - InstallStatusInstallingOther = "installing-other" - InstallStatusInstalled = "installed" -) - -const ( - LangTypeLang = "lang" - LangTypeWebDriver = "webdriver" -) diff --git a/backend/constants/task.go b/backend/constants/task.go deleted file mode 100644 index 08539432..00000000 --- a/backend/constants/task.go +++ /dev/null @@ -1,32 +0,0 @@ -package constants - -const ( - // 调度中 - StatusPending string = "pending" - // 运行中 - StatusRunning string = "running" - // 已完成 - StatusFinished string = "finished" - // 错误 - StatusError string = "error" - // 取消 - StatusCancelled string = "cancelled" - // 节点重启导致的异常终止 - StatusAbnormal string = "abnormal" -) - -const ( - TaskFinish string = "finish" - TaskCancel string = "cancel" -) - -const ( - RunTypeAllNodes string = "all-nodes" - RunTypeRandom string = "random" - RunTypeSelectedNodes string = "selected-nodes" -) - -const ( - TaskTypeSpider string = "spider" - TaskTypeSystem string = "system" -) diff --git a/backend/constants/user.go b/backend/constants/user.go deleted file mode 100644 index bc225c94..00000000 --- a/backend/constants/user.go +++ /dev/null @@ -1,6 +0,0 @@ -package constants - -const ( - RoleAdmin = "admin" - RoleNormal = "normal" -) diff --git a/backend/constants/variable.go b/backend/constants/variable.go deleted file mode 100644 index 713fbe2d..00000000 --- a/backend/constants/variable.go +++ /dev/null @@ -1,9 +0,0 @@ -package constants - -const ( - String = "string" - Number = "number" - Boolean = "boolean" - Array = "array" - Object = "object" -) diff --git a/backend/data/challenge_data.json b/backend/data/challenge_data.json deleted file mode 100644 index 5a51dc33..00000000 --- a/backend/data/challenge_data.json +++ /dev/null @@ -1,142 +0,0 @@ -[ - { - "name": "login_7d", - "title_cn": "连续登录 7 天", - "title_en": "Logged-in for 7 days", - "description_cn": "连续 7 天登录 Crawlab,即可完成挑战!", - "description_en": "Logged-in for consecutive 7 days to complete the challenge", - "difficulty": 1 - }, - { - "name": "login_30d", - "title_cn": "连续登录 30 天", - "title_en": "Logged-in for 30 days", - "description_cn": "连续 30 天登录 Crawlab,即可完成挑战!", - "description_en": "Logged-in for consecutive 30 days to complete the challenge", - "difficulty": 2 - }, - { - "name": "login_90d", - "title_cn": "连续登录 90 天", - "title_en": "Logged-in for 90 days", - "description_cn": "连续 90 天登录 Crawlab,即可完成挑战!", - "description_en": "Logged-in for consecutive 90 days to complete the challenge", - "difficulty": 3 - }, - { - "name": "login_180d", - "title_cn": "连续登录 180 天", - "title_en": "Logged-in for 180 days", - "description_cn": "连续 180 天登录 Crawlab,即可完成挑战!", - "description_en": "Logged-in for consecutive 180 days to complete the challenge", - "difficulty": 4 - }, - { - "name": "create_customized_spider", - "title_cn": "创建 1 个自定义爬虫", - "title_en": "Create a customized spider", - "description_cn": "在爬虫列表中,点击 '添加爬虫',选择 '自定义爬虫',输入相应的参数,点击添加,即可完成挑战!", - "description_en": "In Spider List page, click 'Add Spider', select 'Customized Spider', enter params, click 'Add' to finish the challenge.", - "difficulty": 1, - "path": "/spiders" - }, - { - "name": "create_configurable_spider", - "title_cn": "创建 1 个可配置爬虫", - "title_en": "Create a configurable spider", - "description_cn": "在爬虫列表中,点击 '添加爬虫',选择 '可配置爬虫',输入相应的参数,点击添加,即可完成挑战!", - "description_en": "In Spider List page, click 'Add Spider', select 'Configurable Spider', enter params, click 'Add' to finish the challenge.", - "difficulty": 1, - "path": "/spiders" - }, - { - "name": "run_random", - "title_cn": "用随机模式成功运行爬虫", - "title_en": "Run a spider in random mode successfully", - "description_cn": "在您创建好的爬虫中,导航到其对应的详情页(爬虫列表中点击爬虫),选择随机模式运行一个爬虫,并能运行成功。", - "description_en": "In your created spiders, navigate to corresponding detail page (click spider in Spider List page), run a spider in random mode successfully.", - "difficulty": 1, - "path": "/spiders" - }, - { - "name": "scrape_1k", - "title_cn": "抓取 1 千条数据", - "title_en": "Scrape 1k records", - "description_cn": "运行您创建好的爬虫,抓取 1 千条及以上的结果数据,即可完成挑战!", - "description_en": "Run your created spiders, scrape 1k and more results to finish the challenge.", - "difficulty": 2, - "path": "/spiders" - }, - { - "name": "scrape_10k", - "title_cn": "抓取 1 万条数据", - "title_en": "Scrape 10k records", - "description_cn": "运行您创建好的爬虫,抓取 1 万条及以上的结果数据,即可完成挑战!", - "description_en": "Run your created spiders, scrape 10k and more results to finish the challenge.", - "difficulty": 3, - "path": "/spiders" - }, - { - "name": "scrape_100k", - "title_cn": "抓取 10 万条数据", - "title_en": "Scrape 100k records", - "description_cn": "运行您创建好的爬虫,抓取 10 万条及以上的结果数据,即可完成挑战!", - "description_en": "Run your created spiders, scrape 100k and more results to finish the challenge.", - "difficulty": 4, - "path": "/spiders" - }, - { - "name": "create_schedule", - "title_cn": "创建 1 个定时任务", - "title_en": "Create a schedule", - "description_cn": "在定时任务列表中,创建一个定时任务,正确设置好 Cron 表达式,即可完成挑战!", - "description_en": "In Schedule List page, create a schedule and configure cron expression to finish the task.", - "difficulty": 1, - "path": "/schedules" - }, - { - "name": "create_nodes", - "title_cn": "创建 1 个节点集群", - "title_en": "Create a node cluster", - "description_cn": "按照文档的部署指南,部署含有 3 个节点的集群,即可完成挑战!", - "description_en": "Deploy a 3-node cluster according to the deployment guidance in documentation to finish the task.", - "difficulty": 3, - "path": "/nodes" - }, - { - "name": "install_dep", - "title_cn": "安装 1 个依赖", - "title_en": "Install a dependency successfully", - "description_cn": "在 '节点列表->安装' 或 '节点详情->安装' 中,搜索并安装所需的 1 个依赖,即可完成挑战!", - "description_en": "In 'Node List -> Installation' or 'Node Detail -> Installation', search and install a dependency.", - "difficulty": 3, - "path": "/nodes" - }, - { - "name": "install_lang", - "title_cn": "安装 1 个语言环境", - "title_en": "Install a language successfully", - "description_cn": "在 '节点列表->安装' 或 '节点详情->安装' 中,点击安装所需的 1 个语言环境,即可完成挑战!", - "description_en": "In 'Node List -> Installation' or 'Node Detail -> Installation', install a language.", - "difficulty": 3, - "path": "/nodes" - }, - { - "name": "view_disclaimer", - "title_cn": "阅读免责声明", - "title_en": "View disclaimer", - "description_cn": "在左侧菜单栏,点击 '免责声明' 查看其内容,即可完成挑战!", - "description_en": "In the left side menu, click 'Disclaimer' and view its content to finish the challenge.", - "difficulty": 1, - "path": "/disclaimer" - }, - { - "name": "create_user", - "title_cn": "创建 1 个用户", - "title_en": "Create a user", - "description_cn": "在用户管理页面中创建一个新用户,即可完成挑战!", - "description_en": "In User Admin page, create a new user to finish the challenge.", - "difficulty": 1, - "path": "/users" - } -] \ No newline at end of file diff --git a/backend/database/es_base.go b/backend/database/es_base.go deleted file mode 100644 index b255958a..00000000 --- a/backend/database/es_base.go +++ /dev/null @@ -1,44 +0,0 @@ -package database - -import ( - "context" - "github.com/apex/log" - "github.com/olivere/elastic/v7" - "github.com/satori/go.uuid" - "github.com/spf13/viper" - "sync" - "time" -) - -var doOnce sync.Once -var ctx context.Context -var ESClient *elastic.Client - -func InitEsClient() { - esClientStr := viper.GetString("setting.esClient") - ctx = context.Background() - ESClient, _ = elastic.NewClient(elastic.SetURL(esClientStr), elastic.SetSniff(false)) -} - -// WriteMsg will write the msg and level into es -func WriteMsgToES(when time.Time, msg chan string, index string) { - doOnce.Do(InitEsClient) - vals := make(map[string]interface{}) - vals["@timestamp"] = when.Format(time.RFC3339) - for { - select { - case vals["@msg"] = <-msg: - uid := uuid.NewV4().String() - _, err := ESClient.Index().Index(index).Id(uid).BodyJson(vals).Refresh("wait_for").Do(ctx) - if err != nil { - log.Error(err.Error()) - log.Error("send msg log to es error") - return - } - case <-time.After(6 * time.Second): - return - } - } - - return -} diff --git a/backend/database/mongo.go b/backend/database/mongo.go deleted file mode 100644 index 01204a70..00000000 --- a/backend/database/mongo.go +++ /dev/null @@ -1,112 +0,0 @@ -package database - -import ( - "crawlab/constants" - "github.com/apex/log" - "github.com/cenkalti/backoff/v4" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "github.com/spf13/viper" - "net" - "reflect" - "time" -) - -var Session *mgo.Session - -func GetSession() *mgo.Session { - return Session.Copy() -} - -func GetDb() (*mgo.Session, *mgo.Database) { - s := GetSession() - return s, s.DB(viper.GetString("mongo.db")) -} - -func GetCol(collectionName string) (*mgo.Session, *mgo.Collection) { - s := GetSession() - db := s.DB(viper.GetString("mongo.db")) - col := db.C(collectionName) - return s, col -} - -func GetGridFs(prefix string) (*mgo.Session, *mgo.GridFS) { - s, db := GetDb() - gf := db.GridFS(prefix) - return s, gf -} - -func FillNullObjectId(doc interface{}) { - t := reflect.TypeOf(doc) - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - if t.Kind() != reflect.Struct { - return - } - v := reflect.ValueOf(doc) - for i := 0; i < t.NumField(); i++ { - ft := t.Field(i) - fv := v.Elem().Field(i) - val := fv.Interface() - switch val.(type) { - case bson.ObjectId: - if !val.(bson.ObjectId).Valid() { - v.FieldByName(ft.Name).Set(reflect.ValueOf(bson.ObjectIdHex(constants.ObjectIdNull))) - } - } - } -} - -func InitMongo() error { - var mongoHost = viper.GetString("mongo.host") - var mongoPort = viper.GetString("mongo.port") - var mongoDb = viper.GetString("mongo.db") - var mongoUsername = viper.GetString("mongo.username") - var mongoPassword = viper.GetString("mongo.password") - var mongoAuth = viper.GetString("mongo.authSource") - - if Session == nil { - var dialInfo mgo.DialInfo - addr := net.JoinHostPort(mongoHost, mongoPort) - timeout := time.Second * 10 - dialInfo = mgo.DialInfo{ - Addrs: []string{addr}, - Timeout: timeout, - Database: mongoDb, - PoolLimit: 100, - PoolTimeout: timeout, - ReadTimeout: timeout, - WriteTimeout: timeout, - AppName: "crawlab", - FailFast: true, - MinPoolSize: 10, - MaxIdleTimeMS: 1000 * 30, - } - if mongoUsername != "" { - dialInfo.Username = mongoUsername - dialInfo.Password = mongoPassword - dialInfo.Source = mongoAuth - } - bp := backoff.NewExponentialBackOff() - var err error - - err = backoff.Retry(func() error { - Session, err = mgo.DialWithInfo(&dialInfo) - if err != nil { - log.WithError(err).Warnf("waiting for connect mongo database, after %f seconds try again.", bp.NextBackOff().Seconds()) - } - return err - }, bp) - } - //Add Unique index for 'key' - keyIndex := mgo.Index{ - Key: []string{"key"}, - Unique: true, - } - s, c := GetCol("nodes") - defer s.Close() - c.EnsureIndex(keyIndex) - - return nil -} diff --git a/backend/database/mongo_test.go b/backend/database/mongo_test.go deleted file mode 100644 index ed6044ee..00000000 --- a/backend/database/mongo_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package database - -import ( - "crawlab/config" - "github.com/apex/log" - "github.com/globalsign/mgo" - . "github.com/smartystreets/goconvey/convey" - "github.com/spf13/viper" - "reflect" - "testing" -) - -func init() { - if err := config.InitConfig("../conf/config.yml"); err != nil { - log.Fatal("Init config failed") - } - log.Infof("初始化配置成功") - err := InitMongo() - if err != nil { - log.Fatal("Init mongodb failed") - } - -} - -func TestGetDb(t *testing.T) { - Convey("Test GetDb", t, func() { - if err := config.InitConfig("../conf/config.yml"); err != nil { - t.Fatal("Init config failed") - } - t.Log("初始化配置成功") - err := InitMongo() - if err != nil { - t.Fatal("Init mongodb failed") - } - s, db := GetDb() - Convey("The value should be Session.Copy", func() { - So(s, ShouldResemble, Session.Copy()) - }) - Convey("The value should be reference of database", func() { - So(db, ShouldResemble, s.DB(viper.GetString("mongo.db"))) - }) - }) -} - -func TestGetCol(t *testing.T) { - var c = "nodes" - var colActual *mgo.Collection - Convey("Test GetCol", t, func() { - s, col := GetCol(c) - Convey("s should resemble Session.Copy", func() { - So(s, ShouldResemble, Session.Copy()) - So(reflect.TypeOf(col), ShouldResemble, reflect.TypeOf(colActual)) - }) - }) -} - -func TestGetGridFs(t *testing.T) { - var prefix = "files" - var gfActual *mgo.GridFS - - Convey("Test GetGridFs", t, func() { - s, gf := GetGridFs(prefix) - Convey("s should be session.copy", func() { - So(s, ShouldResemble, Session.Copy()) - }) - Convey("gf should be *mgo.GridFS", func() { - So(reflect.TypeOf(gf), ShouldResemble, reflect.TypeOf(gfActual)) - }) - }) -} diff --git a/backend/database/pubsub.go b/backend/database/pubsub.go deleted file mode 100644 index f9eae535..00000000 --- a/backend/database/pubsub.go +++ /dev/null @@ -1,96 +0,0 @@ -package database - -import ( - "context" - "crawlab/utils" - "fmt" - "github.com/apex/log" - "github.com/gomodule/redigo/redis" - errors2 "github.com/pkg/errors" - "time" -) - -type ConsumeFunc func(message redis.Message) error - -func (r *Redis) Close() { - err := r.pool.Close() - if err != nil { - log.Errorf("redis close error.") - } -} -func (r *Redis) subscribe(ctx context.Context, consume ConsumeFunc, channel ...string) error { - psc := redis.PubSubConn{Conn: r.pool.Get()} - if err := psc.Subscribe(redis.Args{}.AddFlat(channel)...); err != nil { - return err - } - done := make(chan error, 1) - tick := time.NewTicker(time.Second * 3) - defer tick.Stop() - go func() { - defer utils.Close(psc) - for { - switch msg := psc.Receive().(type) { - case error: - done <- fmt.Errorf("redis pubsub receive err: %v", msg) - return - case redis.Message: - if err := consume(msg); err != nil { - fmt.Printf("redis pubsub consume message err: %v", err) - continue - } - case redis.Subscription: - if msg.Count == 0 { - // all channels are unsubscribed - return - } - } - - } - }() - // start a new goroutine to receive message - for { - select { - case <-ctx.Done(): - if err := psc.Unsubscribe(); err != nil { - fmt.Printf("redis pubsub unsubscribe err: %v \n", err) - } - done <- nil - case <-tick.C: - if err := psc.Ping(""); err != nil { - fmt.Printf("ping message error: %s \n", err) - //done <- err - } - case err := <-done: - close(done) - return err - } - } - -} -func (r *Redis) Subscribe(ctx context.Context, consume ConsumeFunc, channel ...string) error { - index := 0 - go func() { - for { - err := r.subscribe(ctx, consume, channel...) - fmt.Println(err) - - if err == nil { - index = 0 - break - } - time.Sleep(5 * time.Second) - index += 1 - fmt.Printf("try reconnect %d times \n", index) - } - }() - return nil -} -func (r *Redis) Publish(channel, message string) (n int, err error) { - conn := r.pool.Get() - defer utils.Close(conn) - n, err = redis.Int(conn.Do("PUBLISH", channel, message)) - if err != nil { - return 0, errors2.Wrapf(err, "redis publish %s %s", channel, message) - } - return -} diff --git a/backend/database/redis.go b/backend/database/redis.go deleted file mode 100644 index e87b688f..00000000 --- a/backend/database/redis.go +++ /dev/null @@ -1,289 +0,0 @@ -package database - -import ( - "context" - "crawlab/entity" - "crawlab/utils" - "errors" - "github.com/apex/log" - "github.com/cenkalti/backoff/v4" - "github.com/gomodule/redigo/redis" - "github.com/spf13/viper" - "runtime/debug" - "strings" - "time" -) - -var RedisClient *Redis - -type Redis struct { - pool *redis.Pool -} - -type Mutex struct { - Name string - expiry time.Duration - tries int - delay time.Duration - value string -} - -func NewRedisClient() *Redis { - return &Redis{pool: NewRedisPool()} -} - -func (r *Redis) RPush(collection string, value interface{}) error { - c := r.pool.Get() - defer utils.Close(c) - - if _, err := c.Do("RPUSH", collection, value); err != nil { - log.Error(err.Error()) - debug.PrintStack() - return err - } - return nil -} - -func (r *Redis) LPush(collection string, value interface{}) error { - c := r.pool.Get() - defer utils.Close(c) - - if _, err := c.Do("RPUSH", collection, value); err != nil { - log.Error(err.Error()) - debug.PrintStack() - return err - } - return nil -} - -func (r *Redis) LPop(collection string) (string, error) { - c := r.pool.Get() - defer utils.Close(c) - - value, err2 := redis.String(c.Do("LPOP", collection)) - if err2 != nil { - return value, err2 - } - return value, nil -} - -func (r *Redis) HSet(collection string, key string, value string) error { - c := r.pool.Get() - defer utils.Close(c) - - if _, err := c.Do("HSET", collection, key, value); err != nil { - log.Error(err.Error()) - debug.PrintStack() - return err - } - return nil -} -func (r *Redis) Ping() error { - c := r.pool.Get() - defer utils.Close(c) - _, err2 := redis.String(c.Do("PING")) - return err2 -} -func (r *Redis) HGet(collection string, key string) (string, error) { - c := r.pool.Get() - defer utils.Close(c) - value, err2 := redis.String(c.Do("HGET", collection, key)) - if err2 != nil && err2 != redis.ErrNil { - log.Error(err2.Error()) - debug.PrintStack() - return value, err2 - } - return value, nil -} - -func (r *Redis) HDel(collection string, key string) error { - c := r.pool.Get() - defer utils.Close(c) - - if _, err := c.Do("HDEL", collection, key); err != nil { - log.Error(err.Error()) - debug.PrintStack() - return err - } - return nil -} -func (r *Redis) HScan(collection string) (results []string, err error) { - c := r.pool.Get() - defer utils.Close(c) - var ( - cursor int64 - items []string - ) - - for { - values, err := redis.Values(c.Do("HSCAN", collection, cursor)) - if err != nil { - return results, err - } - - values, err = redis.Scan(values, &cursor, &items) - if err != nil { - return results, err - } - for i := 0; i < len(items); i += 2 { - cur := items[i+1] - results = append(results, cur) - } - if cursor == 0 { - break - } - } - return results, err - -} -func (r *Redis) HKeys(collection string) ([]string, error) { - c := r.pool.Get() - defer utils.Close(c) - - value, err2 := redis.Strings(c.Do("HKEYS", collection)) - if err2 != nil { - log.Error(err2.Error()) - debug.PrintStack() - return []string{}, err2 - } - return value, nil -} - -func (r *Redis) BRPop(collection string, timeout int) (string, error) { - if timeout <= 0 { - timeout = 60 - } - c := r.pool.Get() - defer utils.Close(c) - - values, err := redis.Strings(c.Do("BRPOP", collection, timeout)) - if err != nil { - return "", err - } - return values[1], nil -} - -func NewRedisPool() *redis.Pool { - var address = viper.GetString("redis.address") - var port = viper.GetString("redis.port") - var database = viper.GetString("redis.database") - var password = viper.GetString("redis.password") - - var url string - if password == "" { - url = "redis://" + address + ":" + port + "/" + database - } else { - url = "redis://x:" + password + "@" + address + ":" + port + "/" + database - } - return &redis.Pool{ - Dial: func() (conn redis.Conn, e error) { - return redis.DialURL(url, - redis.DialConnectTimeout(time.Second*10), - redis.DialReadTimeout(time.Second*600), - redis.DialWriteTimeout(time.Second*10), - ) - }, - TestOnBorrow: func(c redis.Conn, t time.Time) error { - if time.Since(t) < time.Minute { - return nil - } - _, err := c.Do("PING") - return err - }, - MaxIdle: 10, - MaxActive: 0, - IdleTimeout: 300 * time.Second, - Wait: false, - MaxConnLifetime: 0, - } -} - -func InitRedis() error { - RedisClient = NewRedisClient() - b := backoff.NewExponentialBackOff() - b.MaxInterval = 20 * time.Second - err := backoff.Retry(func() error { - err := RedisClient.Ping() - - if err != nil { - log.WithError(err).Warnf("waiting for redis pool active connection. will after %f seconds try again.", b.NextBackOff().Seconds()) - } - return err - }, b) - return err -} - -func Pub(channel string, msg entity.NodeMessage) error { - if _, err := RedisClient.Publish(channel, utils.GetJson(msg)); err != nil { - log.Errorf("publish redis error: %s", err.Error()) - debug.PrintStack() - return err - } - return nil -} - -func Sub(channel string, consume ConsumeFunc) error { - ctx := context.Background() - if err := RedisClient.Subscribe(ctx, consume, channel); err != nil { - log.Errorf("subscribe redis error: %s", err.Error()) - debug.PrintStack() - return err - } - return nil -} - -// 构建同步锁key -func (r *Redis) getLockKey(lockKey string) string { - lockKey = strings.ReplaceAll(lockKey, ":", "-") - return "nodes:lock:" + lockKey -} - -// 获得锁 -func (r *Redis) Lock(lockKey string) (int64, error) { - c := r.pool.Get() - defer utils.Close(c) - lockKey = r.getLockKey(lockKey) - - ts := time.Now().Unix() - ok, err := c.Do("SET", lockKey, ts, "NX", "PX", 30000) - if err != nil { - log.Errorf("get lock fail with error: %s", err.Error()) - debug.PrintStack() - return 0, err - } - if ok == nil { - log.Errorf("the lockKey is locked: key=%s", lockKey) - return 0, errors.New("the lockKey is locked") - } - return ts, nil -} - -func (r *Redis) UnLock(lockKey string, value int64) { - c := r.pool.Get() - defer utils.Close(c) - lockKey = r.getLockKey(lockKey) - - getValue, err := redis.Int64(c.Do("GET", lockKey)) - if err != nil { - log.Errorf("get lockKey error: %s", err.Error()) - debug.PrintStack() - return - } - - if getValue != value { - log.Errorf("the lockKey value diff: %d, %d", value, getValue) - return - } - - v, err := redis.Int64(c.Do("DEL", lockKey)) - if err != nil { - log.Errorf("unlock failed, error: %s", err.Error()) - debug.PrintStack() - return - } - - if v == 0 { - log.Errorf("unlock failed: key=%s", lockKey) - return - } -} diff --git a/backend/docs/docs.go b/backend/docs/docs.go deleted file mode 100644 index feaa3214..00000000 --- a/backend/docs/docs.go +++ /dev/null @@ -1,4808 +0,0 @@ -// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT -// This file was generated by swaggo/swag at -// 2020-05-05 11:09:10.499886 +0800 CST m=+0.084916029 - -package docs - -import ( - "bytes" - "encoding/json" - "strings" - - "github.com/alecthomas/template" - "github.com/swaggo/swag" -) - -var doc = `{ - "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{.Description}}", - "title": "{{.Title}}", - "contact": {}, - "license": {}, - "version": "{{.Version}}" - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": { - "/config_spiders": { - "put": { - "description": "Put config spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Put config spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "spider item", - "name": "spider", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/config_spiders/{id}/config": { - "get": { - "description": "Get config spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Get config spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post config spider config", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Post config spider config", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "spider item", - "name": "spider", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/config_spiders/{id}/spiderfile": { - "post": { - "description": "Post config spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Post config spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/config_spiders/{id}/upload": { - "post": { - "description": "Upload config spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Upload config spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "spider item", - "name": "spider", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/config_spiders_templates": { - "get": { - "description": "Get config spider template list", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Get config spider template list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/docs": { - "get": { - "description": "Get docs", - "produces": [ - "application/json" - ], - "tags": [ - "docs" - ], - "summary": "Get docs", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/file": { - "get": { - "description": "Get file", - "produces": [ - "application/json" - ], - "tags": [ - "file" - ], - "summary": "Get file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes": { - "get": { - "description": "Get nodes", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Get nodes", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}": { - "get": { - "description": "Get node", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Get node", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post node", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Post node", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "post node", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete node", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Delete node", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/deps": { - "get": { - "description": "Get dep list", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get dep list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "language", - "name": "lang", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "dep name", - "name": "dep_name", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/deps/install": { - "post": { - "description": "Install dep", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Install dep", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/deps/installed": { - "get": { - "description": "Get installed dep list", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get installed dep list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "language", - "name": "lang", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/deps/uninstall": { - "post": { - "description": "Uninstall dep", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Uninstall dep", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/langs": { - "get": { - "description": "Get language list", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get language list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/langs/install": { - "post": { - "description": "Install language", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Install language", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/system": { - "get": { - "description": "Get system info", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Get system info", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/tasks": { - "get": { - "description": "Get tasks on node", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Get tasks on node", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/projects": { - "get": { - "description": "Get projects", - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Get projects", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "projects", - "name": "tag", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put project", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Put project", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "post project", - "name": "p", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Project" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/projects/tags": { - "get": { - "description": "Get projects tags", - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Get project tags", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/projects/{id}": { - "post": { - "description": "Post project", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Post project", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "project id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "project item", - "name": "item", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Project" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete project", - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Delete project", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "project id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/releases/latest": { - "get": { - "description": "Get latest release", - "produces": [ - "application/json" - ], - "tags": [ - "version" - ], - "summary": "Get latest release", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/schedules": { - "get": { - "description": "Get spider list", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "page num", - "name": "page_num", - "in": "query" - }, - { - "type": "string", - "description": "page size", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "keyword", - "name": "keyword", - "in": "query" - }, - { - "type": "string", - "description": "project_id", - "name": "project_id", - "in": "query" - }, - { - "type": "string", - "description": "type", - "name": "type", - "in": "query" - }, - { - "type": "string", - "description": "sort_key", - "name": "sort_key", - "in": "query" - }, - { - "type": "string", - "description": "sort_direction", - "name": "sort_direction", - "in": "query" - }, - { - "type": "string", - "description": "owner_type", - "name": "owner_type", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put schedule", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "Put schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "schedule item", - "name": "item", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Schedule" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/schedules/{id}": { - "get": { - "description": "Get schedule by id", - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "Get schedule by id", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post schedule", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "Post schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "schedule item", - "name": "newItem", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Schedule" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete schedule", - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "Delete schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/schedules/{id}/disable": { - "post": { - "description": "disable schedule", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "disable schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/schedules/{id}/enable": { - "post": { - "description": "enable schedule", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "enable schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/setting": { - "get": { - "description": "Get setting", - "produces": [ - "application/json" - ], - "tags": [ - "setting" - ], - "summary": "Get setting", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders": { - "put": { - "description": "Put spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Put spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "spider item", - "name": "spider", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "delete spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "delete spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders-cancel": { - "post": { - "description": "cancel spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "cancel spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders-run": { - "post": { - "description": "run spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "run spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}": { - "get": { - "description": "Get spider by id", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider by id", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "spider item", - "name": "item", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete spider by id", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Delete spider by id", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/copy": { - "post": { - "description": "Copy spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Copy spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/dir": { - "get": { - "description": "Get spider dir", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider dir", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "path", - "name": "path", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/file": { - "get": { - "description": "Get spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "path", - "name": "path", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Post spider dir", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post spider dir", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "path", - "name": "reqBody", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.SpiderFileReqBody" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Put spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Put spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "path", - "name": "reqBody", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.SpiderFileReqBody" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Delete spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "path", - "name": "reqBody", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.SpiderFileReqBody" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/file/rename": { - "post": { - "description": "Rename spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Rename spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "path", - "name": "reqBody", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.SpiderFileReqBody" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/file/tree": { - "get": { - "description": "Get spider dir", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider dir", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/git/reset": { - "post": { - "description": "Post spider reset git", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post spider reset git", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/git/sync": { - "post": { - "description": "Post spider sync git", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post spider sync git", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/publish": { - "post": { - "description": "Publish spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Publish spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/schedules": { - "get": { - "description": "Get schedules", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get schedules", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/items": { - "get": { - "description": "Get scrapy spider items", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider items", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post scrapy spider items", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post scrapy spider items", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "req data", - "name": "reqData", - "in": "body", - "required": true, - "schema": { - "type": "entity.ScrapyItem", - "items": { - "$ref": "#/definitions/entity.ScrapyItem" - } - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/pipelines": { - "get": { - "description": "Get scrapy spider pipelines", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider pipelines", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/settings": { - "get": { - "description": "Get scrapy spider settings", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider settings", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Get scrapy spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "req data", - "name": "reqData", - "in": "body", - "required": true, - "schema": { - "type": "entity.ScrapySettingParam", - "items": { - "$ref": "#/definitions/entity.ScrapySettingParam" - } - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/spider/filepath": { - "get": { - "description": "Get scrapy spider file path", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider file path", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/spiders": { - "get": { - "description": "Get scrapy spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put scrapy spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Put scrapy spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/stats": { - "get": { - "description": "Get spider stats", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider stats", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/tasks": { - "get": { - "description": "Get task list", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get task list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/upload": { - "post": { - "description": "Upload spider by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Upload spider by id", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "file", - "description": "spider file to upload", - "name": "file", - "in": "formData", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/stats/home": { - "get": { - "description": "Get home stats", - "produces": [ - "application/json" - ], - "tags": [ - "version" - ], - "summary": "Get home stats", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/system/deps/": { - "get": { - "description": "Get all dep list", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get all dep list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "language", - "name": "lang", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "dep name", - "name": "dep_nane", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/system/deps/{lang}/{dep_name}/json": { - "get": { - "description": "Get dep json", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get dep json", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "language", - "name": "lang", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "dep name", - "name": "dep_name", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/task/{id}": { - "delete": { - "description": "Delete task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Delete task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks": { - "get": { - "description": "Get task list", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "req data", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.TaskListRequestData" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Put task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete tasks", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Delete tasks", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}": { - "get": { - "description": "Get task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/cancel": { - "post": { - "description": "Cancel task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Cancel task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/error-log": { - "delete": { - "description": "Get task error log", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task error log", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/log": { - "delete": { - "description": "Get task log", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task log", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/restart": { - "post": { - "description": "Restart task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Restart task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/results": { - "get": { - "description": "Get task list", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "req data", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.TaskResultsRequestData" - } - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/results/download": { - "get": { - "description": "Get task results", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task results", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks_by_status": { - "delete": { - "description": "Delete task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Delete task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task status", - "name": "status", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tokens": { - "get": { - "description": "token", - "produces": [ - "application/json" - ], - "tags": [ - "token" - ], - "summary": "Get token", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "token", - "produces": [ - "application/json" - ], - "tags": [ - "token" - ], - "summary": "Put token", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tokens/{id}": { - "delete": { - "description": "Delete token", - "produces": [ - "application/json" - ], - "tags": [ - "token" - ], - "summary": "Delete token", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "token id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/users": { - "get": { - "description": "Get user list", - "produces": [ - "application/json" - ], - "tags": [ - "token" - ], - "summary": "Get user list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "data body", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.UserListRequestData" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put user", - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Put user", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "reqData body", - "name": "reqData", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.UserRequestData" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/users/{id}": { - "get": { - "description": "user", - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "user id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post user", - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Post user", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "user body", - "name": "item", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.User" - } - }, - { - "type": "string", - "description": "user id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete user", - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Delete user", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "user id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/variable": { - "put": { - "description": "Put variable", - "produces": [ - "application/json" - ], - "tags": [ - "variable" - ], - "summary": "Put variable", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "reqData body", - "name": "variable", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Variable" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/variable/{id}": { - "post": { - "description": "Post variable", - "produces": [ - "application/json" - ], - "tags": [ - "variable" - ], - "summary": "Post variable", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "reqData body", - "name": "variable", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Variable" - } - }, - { - "type": "string", - "description": "variable id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete variable", - "produces": [ - "application/json" - ], - "tags": [ - "variable" - ], - "summary": "Delete variable", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "variable id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/variables": { - "get": { - "description": "Get variable list", - "produces": [ - "application/json" - ], - "tags": [ - "variable" - ], - "summary": "Get variable list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/version": { - "get": { - "description": "Get version", - "produces": [ - "application/json" - ], - "tags": [ - "setting" - ], - "summary": "Get version", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - } - }, - "definitions": { - "entity.ConfigSpiderData": { - "type": "object", - "properties": { - "cmd": { - "description": "自定义爬虫", - "type": "string" - }, - "col": { - "type": "string" - }, - "display_name": { - "type": "string" - }, - "engine": { - "description": "可配置爬虫", - "type": "string" - }, - "name": { - "description": "通用", - "type": "string" - }, - "remark": { - "type": "string" - }, - "settings": { - "type": "object" - }, - "stages": { - "type": "array", - "items": { - "$ref": "#/definitions/entity.Stage" - } - }, - "start_stage": { - "type": "string" - }, - "start_url": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "entity.Field": { - "type": "object", - "properties": { - "attr": { - "type": "string" - }, - "css": { - "type": "string" - }, - "name": { - "type": "string" - }, - "next_stage": { - "type": "string" - }, - "remark": { - "type": "string" - }, - "xpath": { - "type": "string" - } - } - }, - "entity.ScrapyItem": { - "type": "object", - "properties": { - "fields": { - "type": "array", - "items": { - "type": "string" - } - }, - "name": { - "type": "string" - } - } - }, - "entity.ScrapySettingParam": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "type": { - "type": "string" - }, - "value": { - "type": "object" - } - } - }, - "entity.Stage": { - "type": "object", - "properties": { - "fields": { - "type": "array", - "items": { - "$ref": "#/definitions/entity.Field" - } - }, - "is_list": { - "type": "boolean" - }, - "list_css": { - "type": "string" - }, - "list_xpath": { - "type": "string" - }, - "name": { - "type": "string" - }, - "page_attr": { - "type": "string" - }, - "page_css": { - "type": "string" - }, - "page_xpath": { - "type": "string" - } - } - }, - "model.Env": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "model.Node": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "description": { - "type": "string" - }, - "hostname": { - "type": "string" - }, - "ip": { - "type": "string" - }, - "is_master": { - "description": "前端展示", - "type": "boolean" - }, - "key": { - "description": "用于唯一标识节点,可能是mac地址,可能是ip地址", - "type": "string" - }, - "mac": { - "type": "string" - }, - "name": { - "type": "string" - }, - "port": { - "type": "string" - }, - "status": { - "type": "string" - }, - "update_ts": { - "type": "string" - }, - "update_ts_unix": { - "type": "integer" - } - } - }, - "model.Project": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "spiders": { - "description": "前端展示", - "type": "array", - "items": { - "$ref": "#/definitions/model.Spider" - } - }, - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "type": "string" - }, - "username": { - "type": "string" - } - } - }, - "model.Schedule": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "cron": { - "type": "string" - }, - "description": { - "type": "string" - }, - "enabled": { - "type": "boolean" - }, - "entry_id": { - "type": "integer" - }, - "message": { - "type": "string" - }, - "name": { - "type": "string" - }, - "node_ids": { - "type": "array", - "items": { - "type": "string" - } - }, - "nodes": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Node" - } - }, - "param": { - "type": "string" - }, - "run_type": { - "type": "string" - }, - "scrapy_log_level": { - "type": "string" - }, - "scrapy_spider": { - "type": "string" - }, - "spider_id": { - "type": "string" - }, - "spider_name": { - "description": "前端展示", - "type": "string" - }, - "status": { - "type": "string" - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "type": "string" - }, - "user_name": { - "type": "string" - } - } - }, - "model.Spider": { - "type": "object", - "properties": { - "_id": { - "description": "爬虫ID", - "type": "string" - }, - "cmd": { - "description": "自定义爬虫", - "type": "string" - }, - "col": { - "description": "结果储存位置", - "type": "string" - }, - "config": { - "description": "可配置爬虫配置", - "type": "object", - "$ref": "#/definitions/entity.ConfigSpiderData" - }, - "create_ts": { - "type": "string" - }, - "dedup_field": { - "description": "去重字段", - "type": "string" - }, - "dedup_method": { - "description": "去重方式", - "type": "string" - }, - "display_name": { - "description": "爬虫显示名称", - "type": "string" - }, - "envs": { - "description": "环境变量", - "type": "array", - "items": { - "$ref": "#/definitions/model.Env" - } - }, - "file_id": { - "description": "GridFS文件ID", - "type": "string" - }, - "git_auto_sync": { - "description": "Git 是否自动同步", - "type": "boolean" - }, - "git_branch": { - "description": "Git 分支", - "type": "string" - }, - "git_has_credential": { - "description": "Git 是否加密", - "type": "boolean" - }, - "git_password": { - "description": "Git 密码", - "type": "string" - }, - "git_sync_error": { - "description": "Git 同步错误", - "type": "string" - }, - "git_sync_frequency": { - "description": "Git 同步频率", - "type": "string" - }, - "git_url": { - "description": "Git URL", - "type": "string" - }, - "git_username": { - "description": "Git 用户名", - "type": "string" - }, - "is_dedup": { - "description": "去重", - "type": "boolean" - }, - "is_git": { - "description": "Git 设置", - "type": "boolean" - }, - "is_long_task": { - "description": "长任务", - "type": "boolean" - }, - "is_public": { - "description": "是否公开", - "type": "boolean" - }, - "is_scrapy": { - "description": "Scrapy 爬虫(属于自定义爬虫)", - "type": "boolean" - }, - "is_web_hook": { - "description": "Web Hook", - "type": "boolean" - }, - "last_run_ts": { - "description": "前端展示", - "type": "string" - }, - "last_status": { - "description": "最后执行状态", - "type": "string" - }, - "latest_tasks": { - "description": "最近任务列表", - "type": "array", - "items": { - "$ref": "#/definitions/model.Task" - } - }, - "name": { - "description": "爬虫名称(唯一)", - "type": "string" - }, - "project_id": { - "description": "项目ID", - "type": "string" - }, - "remark": { - "description": "备注", - "type": "string" - }, - "site": { - "description": "爬虫网站", - "type": "string" - }, - "spider_names": { - "description": "爬虫名称列表", - "type": "array", - "items": { - "type": "string" - } - }, - "src": { - "description": "源码位置", - "type": "string" - }, - "template": { - "description": "可配置爬虫", - "type": "string" - }, - "type": { - "description": "爬虫类别", - "type": "string" - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "description": "时间", - "type": "string" - }, - "username": { - "description": "用户名称", - "type": "string" - }, - "web_hook_url": { - "description": "Web Hook URL", - "type": "string" - } - } - }, - "model.Task": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "cmd": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "error": { - "type": "string" - }, - "error_log_count": { - "type": "integer" - }, - "finish_ts": { - "type": "string" - }, - "log_path": { - "type": "string" - }, - "node_id": { - "type": "string" - }, - "node_name": { - "type": "string" - }, - "param": { - "type": "string" - }, - "pid": { - "type": "integer" - }, - "result_count": { - "type": "integer" - }, - "run_type": { - "type": "string" - }, - "runtime_duration": { - "type": "number" - }, - "schedule_id": { - "type": "string" - }, - "spider_id": { - "type": "string" - }, - "spider_name": { - "description": "前端数据", - "type": "string" - }, - "start_ts": { - "type": "string" - }, - "status": { - "type": "string" - }, - "total_duration": { - "type": "number" - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "type": "string" - }, - "username": { - "type": "string" - }, - "wait_duration": { - "type": "number" - } - } - }, - "model.User": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "email": { - "type": "string" - }, - "password": { - "type": "string" - }, - "role": { - "type": "string" - }, - "setting": { - "type": "object", - "$ref": "#/definitions/model.UserSetting" - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "type": "string" - }, - "username": { - "type": "string" - } - } - }, - "model.UserSetting": { - "type": "object", - "properties": { - "ding_talk_robot_webhook": { - "type": "string" - }, - "enabled_notifications": { - "type": "array", - "items": { - "type": "string" - } - }, - "error_regex_pattern": { - "type": "string" - }, - "log_expire_duration": { - "type": "integer" - }, - "max_error_log": { - "type": "integer" - }, - "notification_trigger": { - "type": "string" - }, - "wechat_robot_webhook": { - "type": "string" - } - } - }, - "model.Variable": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "key": { - "type": "string" - }, - "remark": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "routes.SpiderFileReqBody": { - "type": "object", - "properties": { - "content": { - "type": "string" - }, - "new_path": { - "type": "string" - }, - "path": { - "type": "string" - } - } - }, - "routes.TaskListRequestData": { - "type": "object", - "properties": { - "nodeId": { - "type": "string" - }, - "pageNum": { - "type": "integer" - }, - "pageSize": { - "type": "integer" - }, - "scheduleId": { - "type": "string" - }, - "spiderId": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, - "routes.TaskResultsRequestData": { - "type": "object", - "properties": { - "pageNum": { - "type": "integer" - }, - "pageSize": { - "type": "integer" - } - } - }, - "routes.UserListRequestData": { - "type": "object", - "properties": { - "pageNum": { - "type": "integer" - }, - "pageSize": { - "type": "integer" - } - } - }, - "routes.UserRequestData": { - "type": "object", - "properties": { - "email": { - "type": "string" - }, - "password": { - "type": "string" - }, - "role": { - "type": "string" - }, - "username": { - "type": "string" - } - } - } - } -}` - -type swaggerInfo struct { - Version string - Host string - BasePath string - Schemes []string - Title string - Description string -} - -// SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = swaggerInfo{ - Version: "", - Host: "", - BasePath: "", - Schemes: []string{}, - Title: "", - Description: "", -} - -type s struct{} - -func (s *s) ReadDoc() string { - sInfo := SwaggerInfo - sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1) - - t, err := template.New("swagger_info").Funcs(template.FuncMap{ - "marshal": func(v interface{}) string { - a, _ := json.Marshal(v) - return string(a) - }, - }).Parse(doc) - if err != nil { - return doc - } - - var tpl bytes.Buffer - if err := t.Execute(&tpl, sInfo); err != nil { - return doc - } - - return tpl.String() -} - -func init() { - swag.Register(swag.Name, &s{}) -} diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json deleted file mode 100644 index 47986662..00000000 --- a/backend/docs/swagger.json +++ /dev/null @@ -1,4740 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "contact": {}, - "license": {} - }, - "paths": { - "/config_spiders": { - "put": { - "description": "Put config spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Put config spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "spider item", - "name": "spider", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/config_spiders/{id}/config": { - "get": { - "description": "Get config spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Get config spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post config spider config", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Post config spider config", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "spider item", - "name": "spider", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/config_spiders/{id}/spiderfile": { - "post": { - "description": "Post config spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Post config spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/config_spiders/{id}/upload": { - "post": { - "description": "Upload config spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Upload config spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "spider item", - "name": "spider", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/config_spiders_templates": { - "get": { - "description": "Get config spider template list", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "config spider" - ], - "summary": "Get config spider template list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/docs": { - "get": { - "description": "Get docs", - "produces": [ - "application/json" - ], - "tags": [ - "docs" - ], - "summary": "Get docs", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/file": { - "get": { - "description": "Get file", - "produces": [ - "application/json" - ], - "tags": [ - "file" - ], - "summary": "Get file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes": { - "get": { - "description": "Get nodes", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Get nodes", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}": { - "get": { - "description": "Get node", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Get node", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post node", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Post node", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "post node", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete node", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Delete node", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/deps": { - "get": { - "description": "Get dep list", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get dep list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "language", - "name": "lang", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "dep name", - "name": "dep_name", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/deps/install": { - "post": { - "description": "Install dep", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Install dep", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/deps/installed": { - "get": { - "description": "Get installed dep list", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get installed dep list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "language", - "name": "lang", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/deps/uninstall": { - "post": { - "description": "Uninstall dep", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Uninstall dep", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/langs": { - "get": { - "description": "Get language list", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get language list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/langs/install": { - "post": { - "description": "Install language", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Install language", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/system": { - "get": { - "description": "Get system info", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Get system info", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/nodes/{id}/tasks": { - "get": { - "description": "Get tasks on node", - "produces": [ - "application/json" - ], - "tags": [ - "node" - ], - "summary": "Get tasks on node", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "node id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/projects": { - "get": { - "description": "Get projects", - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Get projects", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "projects", - "name": "tag", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put project", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Put project", - "parameters": [ - { - "type": "string", - "description": "With the bearer started", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "post project", - "name": "p", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Project" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/projects/tags": { - "get": { - "description": "Get projects tags", - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Get project tags", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/projects/{id}": { - "post": { - "description": "Post project", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Post project", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "project id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "project item", - "name": "item", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Project" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete project", - "produces": [ - "application/json" - ], - "tags": [ - "project" - ], - "summary": "Delete project", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "project id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/releases/latest": { - "get": { - "description": "Get latest release", - "produces": [ - "application/json" - ], - "tags": [ - "version" - ], - "summary": "Get latest release", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/schedules": { - "get": { - "description": "Get spider list", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "page num", - "name": "page_num", - "in": "query" - }, - { - "type": "string", - "description": "page size", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "keyword", - "name": "keyword", - "in": "query" - }, - { - "type": "string", - "description": "project_id", - "name": "project_id", - "in": "query" - }, - { - "type": "string", - "description": "type", - "name": "type", - "in": "query" - }, - { - "type": "string", - "description": "sort_key", - "name": "sort_key", - "in": "query" - }, - { - "type": "string", - "description": "sort_direction", - "name": "sort_direction", - "in": "query" - }, - { - "type": "string", - "description": "owner_type", - "name": "owner_type", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put schedule", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "Put schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "schedule item", - "name": "item", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Schedule" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/schedules/{id}": { - "get": { - "description": "Get schedule by id", - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "Get schedule by id", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post schedule", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "Post schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "schedule item", - "name": "newItem", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Schedule" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete schedule", - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "Delete schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/schedules/{id}/disable": { - "post": { - "description": "disable schedule", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "disable schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/schedules/{id}/enable": { - "post": { - "description": "enable schedule", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "schedule" - ], - "summary": "enable schedule", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/setting": { - "get": { - "description": "Get setting", - "produces": [ - "application/json" - ], - "tags": [ - "setting" - ], - "summary": "Get setting", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders": { - "put": { - "description": "Put spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Put spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "spider item", - "name": "spider", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "delete spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "delete spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders-cancel": { - "post": { - "description": "cancel spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "cancel spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders-run": { - "post": { - "description": "run spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "run spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}": { - "get": { - "description": "Get spider by id", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider by id", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "spider item", - "name": "item", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Spider" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete spider by id", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Delete spider by id", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/copy": { - "post": { - "description": "Copy spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Copy spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/dir": { - "get": { - "description": "Get spider dir", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider dir", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "path", - "name": "path", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/file": { - "get": { - "description": "Get spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "path", - "name": "path", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Post spider dir", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post spider dir", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "path", - "name": "reqBody", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.SpiderFileReqBody" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Put spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Put spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "path", - "name": "reqBody", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.SpiderFileReqBody" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Delete spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "path", - "name": "reqBody", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.SpiderFileReqBody" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/file/rename": { - "post": { - "description": "Rename spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Rename spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "path", - "name": "reqBody", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.SpiderFileReqBody" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/file/tree": { - "get": { - "description": "Get spider dir", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider dir", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/git/reset": { - "post": { - "description": "Post spider reset git", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post spider reset git", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/git/sync": { - "post": { - "description": "Post spider sync git", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post spider sync git", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/publish": { - "post": { - "description": "Publish spider", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Publish spider", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "schedule id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/schedules": { - "get": { - "description": "Get schedules", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get schedules", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/items": { - "get": { - "description": "Get scrapy spider items", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider items", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post scrapy spider items", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Post scrapy spider items", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "req data", - "name": "reqData", - "in": "body", - "required": true, - "schema": { - "type": "entity.ScrapyItem", - "items": { - "$ref": "#/definitions/entity.ScrapyItem" - } - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/pipelines": { - "get": { - "description": "Get scrapy spider pipelines", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider pipelines", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/settings": { - "get": { - "description": "Get scrapy spider settings", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider settings", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Get scrapy spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "req data", - "name": "reqData", - "in": "body", - "required": true, - "schema": { - "type": "entity.ScrapySettingParam", - "items": { - "$ref": "#/definitions/entity.ScrapySettingParam" - } - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/spider/filepath": { - "get": { - "description": "Get scrapy spider file path", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider file path", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/scrapy/spiders": { - "get": { - "description": "Get scrapy spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get scrapy spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put scrapy spider file", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Put scrapy spider file", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/stats": { - "get": { - "description": "Get spider stats", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get spider stats", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/tasks": { - "get": { - "description": "Get task list", - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Get task list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/spiders/{id}/upload": { - "post": { - "description": "Upload spider by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spider" - ], - "summary": "Upload spider by id", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "file", - "description": "spider file to upload", - "name": "file", - "in": "formData", - "required": true - }, - { - "type": "string", - "description": "spider id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "json" - } - } - } - } - }, - "/stats/home": { - "get": { - "description": "Get home stats", - "produces": [ - "application/json" - ], - "tags": [ - "version" - ], - "summary": "Get home stats", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/system/deps/": { - "get": { - "description": "Get all dep list", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get all dep list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "language", - "name": "lang", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "dep name", - "name": "dep_nane", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/system/deps/{lang}/{dep_name}/json": { - "get": { - "description": "Get dep json", - "produces": [ - "application/json" - ], - "tags": [ - "system" - ], - "summary": "Get dep json", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "language", - "name": "lang", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "dep name", - "name": "dep_name", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/task/{id}": { - "delete": { - "description": "Delete task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Delete task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks": { - "get": { - "description": "Get task list", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "req data", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.TaskListRequestData" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Put task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete tasks", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Delete tasks", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}": { - "get": { - "description": "Get task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/cancel": { - "post": { - "description": "Cancel task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Cancel task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/error-log": { - "delete": { - "description": "Get task error log", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task error log", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/log": { - "delete": { - "description": "Get task log", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task log", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/restart": { - "post": { - "description": "Restart task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Restart task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/results": { - "get": { - "description": "Get task list", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "req data", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.TaskResultsRequestData" - } - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks/{id}/results/download": { - "get": { - "description": "Get task results", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Get task results", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tasks_by_status": { - "delete": { - "description": "Delete task", - "produces": [ - "application/json" - ], - "tags": [ - "task" - ], - "summary": "Delete task", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "task status", - "name": "status", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tokens": { - "get": { - "description": "token", - "produces": [ - "application/json" - ], - "tags": [ - "token" - ], - "summary": "Get token", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "token", - "produces": [ - "application/json" - ], - "tags": [ - "token" - ], - "summary": "Put token", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/tokens/{id}": { - "delete": { - "description": "Delete token", - "produces": [ - "application/json" - ], - "tags": [ - "token" - ], - "summary": "Delete token", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "token id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/users": { - "get": { - "description": "Get user list", - "produces": [ - "application/json" - ], - "tags": [ - "token" - ], - "summary": "Get user list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "data body", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.UserListRequestData" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "put": { - "description": "Put user", - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Put user", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "reqData body", - "name": "reqData", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/routes.UserRequestData" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/users/{id}": { - "get": { - "description": "user", - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "user id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "post": { - "description": "Post user", - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Post user", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "user body", - "name": "item", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.User" - } - }, - { - "type": "string", - "description": "user id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete user", - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Delete user", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "user id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/variable": { - "put": { - "description": "Put variable", - "produces": [ - "application/json" - ], - "tags": [ - "variable" - ], - "summary": "Put variable", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "reqData body", - "name": "variable", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Variable" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/variable/{id}": { - "post": { - "description": "Post variable", - "produces": [ - "application/json" - ], - "tags": [ - "variable" - ], - "summary": "Post variable", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "description": "reqData body", - "name": "variable", - "in": "body", - "required": true, - "schema": { - "type": "object", - "$ref": "#/definitions/model.Variable" - } - }, - { - "type": "string", - "description": "variable id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - }, - "delete": { - "description": "Delete variable", - "produces": [ - "application/json" - ], - "tags": [ - "variable" - ], - "summary": "Delete variable", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - }, - { - "type": "string", - "description": "variable id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/variables": { - "get": { - "description": "Get variable list", - "produces": [ - "application/json" - ], - "tags": [ - "variable" - ], - "summary": "Get variable list", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - }, - "/version": { - "get": { - "description": "Get version", - "produces": [ - "application/json" - ], - "tags": [ - "setting" - ], - "summary": "Get version", - "parameters": [ - { - "type": "string", - "description": "Authorization token", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "json" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "json" - } - } - } - } - } - }, - "definitions": { - "entity.ConfigSpiderData": { - "type": "object", - "properties": { - "cmd": { - "description": "自定义爬虫", - "type": "string" - }, - "col": { - "type": "string" - }, - "display_name": { - "type": "string" - }, - "engine": { - "description": "可配置爬虫", - "type": "string" - }, - "name": { - "description": "通用", - "type": "string" - }, - "remark": { - "type": "string" - }, - "settings": { - "type": "object" - }, - "stages": { - "type": "array", - "items": { - "$ref": "#/definitions/entity.Stage" - } - }, - "start_stage": { - "type": "string" - }, - "start_url": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "entity.Field": { - "type": "object", - "properties": { - "attr": { - "type": "string" - }, - "css": { - "type": "string" - }, - "name": { - "type": "string" - }, - "next_stage": { - "type": "string" - }, - "remark": { - "type": "string" - }, - "xpath": { - "type": "string" - } - } - }, - "entity.ScrapyItem": { - "type": "object", - "properties": { - "fields": { - "type": "array", - "items": { - "type": "string" - } - }, - "name": { - "type": "string" - } - } - }, - "entity.ScrapySettingParam": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "type": { - "type": "string" - }, - "value": { - "type": "object" - } - } - }, - "entity.Stage": { - "type": "object", - "properties": { - "fields": { - "type": "array", - "items": { - "$ref": "#/definitions/entity.Field" - } - }, - "is_list": { - "type": "boolean" - }, - "list_css": { - "type": "string" - }, - "list_xpath": { - "type": "string" - }, - "name": { - "type": "string" - }, - "page_attr": { - "type": "string" - }, - "page_css": { - "type": "string" - }, - "page_xpath": { - "type": "string" - } - } - }, - "model.Env": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "model.Node": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "description": { - "type": "string" - }, - "hostname": { - "type": "string" - }, - "ip": { - "type": "string" - }, - "is_master": { - "description": "前端展示", - "type": "boolean" - }, - "key": { - "description": "用于唯一标识节点,可能是mac地址,可能是ip地址", - "type": "string" - }, - "mac": { - "type": "string" - }, - "name": { - "type": "string" - }, - "port": { - "type": "string" - }, - "status": { - "type": "string" - }, - "update_ts": { - "type": "string" - }, - "update_ts_unix": { - "type": "integer" - } - } - }, - "model.Project": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "spiders": { - "description": "前端展示", - "type": "array", - "items": { - "$ref": "#/definitions/model.Spider" - } - }, - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "type": "string" - }, - "username": { - "type": "string" - } - } - }, - "model.Schedule": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "cron": { - "type": "string" - }, - "description": { - "type": "string" - }, - "enabled": { - "type": "boolean" - }, - "entry_id": { - "type": "integer" - }, - "message": { - "type": "string" - }, - "name": { - "type": "string" - }, - "node_ids": { - "type": "array", - "items": { - "type": "string" - } - }, - "nodes": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Node" - } - }, - "param": { - "type": "string" - }, - "run_type": { - "type": "string" - }, - "scrapy_log_level": { - "type": "string" - }, - "scrapy_spider": { - "type": "string" - }, - "spider_id": { - "type": "string" - }, - "spider_name": { - "description": "前端展示", - "type": "string" - }, - "status": { - "type": "string" - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "type": "string" - }, - "user_name": { - "type": "string" - } - } - }, - "model.Spider": { - "type": "object", - "properties": { - "_id": { - "description": "爬虫ID", - "type": "string" - }, - "cmd": { - "description": "自定义爬虫", - "type": "string" - }, - "col": { - "description": "结果储存位置", - "type": "string" - }, - "config": { - "description": "可配置爬虫配置", - "type": "object", - "$ref": "#/definitions/entity.ConfigSpiderData" - }, - "create_ts": { - "type": "string" - }, - "dedup_field": { - "description": "去重字段", - "type": "string" - }, - "dedup_method": { - "description": "去重方式", - "type": "string" - }, - "display_name": { - "description": "爬虫显示名称", - "type": "string" - }, - "envs": { - "description": "环境变量", - "type": "array", - "items": { - "$ref": "#/definitions/model.Env" - } - }, - "file_id": { - "description": "GridFS文件ID", - "type": "string" - }, - "git_auto_sync": { - "description": "Git 是否自动同步", - "type": "boolean" - }, - "git_branch": { - "description": "Git 分支", - "type": "string" - }, - "git_has_credential": { - "description": "Git 是否加密", - "type": "boolean" - }, - "git_password": { - "description": "Git 密码", - "type": "string" - }, - "git_sync_error": { - "description": "Git 同步错误", - "type": "string" - }, - "git_sync_frequency": { - "description": "Git 同步频率", - "type": "string" - }, - "git_url": { - "description": "Git URL", - "type": "string" - }, - "git_username": { - "description": "Git 用户名", - "type": "string" - }, - "is_dedup": { - "description": "去重", - "type": "boolean" - }, - "is_git": { - "description": "Git 设置", - "type": "boolean" - }, - "is_long_task": { - "description": "长任务", - "type": "boolean" - }, - "is_public": { - "description": "是否公开", - "type": "boolean" - }, - "is_scrapy": { - "description": "Scrapy 爬虫(属于自定义爬虫)", - "type": "boolean" - }, - "is_web_hook": { - "description": "Web Hook", - "type": "boolean" - }, - "last_run_ts": { - "description": "前端展示", - "type": "string" - }, - "last_status": { - "description": "最后执行状态", - "type": "string" - }, - "latest_tasks": { - "description": "最近任务列表", - "type": "array", - "items": { - "$ref": "#/definitions/model.Task" - } - }, - "name": { - "description": "爬虫名称(唯一)", - "type": "string" - }, - "project_id": { - "description": "项目ID", - "type": "string" - }, - "remark": { - "description": "备注", - "type": "string" - }, - "site": { - "description": "爬虫网站", - "type": "string" - }, - "spider_names": { - "description": "爬虫名称列表", - "type": "array", - "items": { - "type": "string" - } - }, - "src": { - "description": "源码位置", - "type": "string" - }, - "template": { - "description": "可配置爬虫", - "type": "string" - }, - "type": { - "description": "爬虫类别", - "type": "string" - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "description": "时间", - "type": "string" - }, - "username": { - "description": "用户名称", - "type": "string" - }, - "web_hook_url": { - "description": "Web Hook URL", - "type": "string" - } - } - }, - "model.Task": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "cmd": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "error": { - "type": "string" - }, - "error_log_count": { - "type": "integer" - }, - "finish_ts": { - "type": "string" - }, - "log_path": { - "type": "string" - }, - "node_id": { - "type": "string" - }, - "node_name": { - "type": "string" - }, - "param": { - "type": "string" - }, - "pid": { - "type": "integer" - }, - "result_count": { - "type": "integer" - }, - "run_type": { - "type": "string" - }, - "runtime_duration": { - "type": "number" - }, - "schedule_id": { - "type": "string" - }, - "spider_id": { - "type": "string" - }, - "spider_name": { - "description": "前端数据", - "type": "string" - }, - "start_ts": { - "type": "string" - }, - "status": { - "type": "string" - }, - "total_duration": { - "type": "number" - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "type": "string" - }, - "username": { - "type": "string" - }, - "wait_duration": { - "type": "number" - } - } - }, - "model.User": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "create_ts": { - "type": "string" - }, - "email": { - "type": "string" - }, - "password": { - "type": "string" - }, - "role": { - "type": "string" - }, - "setting": { - "type": "object", - "$ref": "#/definitions/model.UserSetting" - }, - "update_ts": { - "type": "string" - }, - "user_id": { - "type": "string" - }, - "username": { - "type": "string" - } - } - }, - "model.UserSetting": { - "type": "object", - "properties": { - "ding_talk_robot_webhook": { - "type": "string" - }, - "enabled_notifications": { - "type": "array", - "items": { - "type": "string" - } - }, - "error_regex_pattern": { - "type": "string" - }, - "log_expire_duration": { - "type": "integer" - }, - "max_error_log": { - "type": "integer" - }, - "notification_trigger": { - "type": "string" - }, - "wechat_robot_webhook": { - "type": "string" - } - } - }, - "model.Variable": { - "type": "object", - "properties": { - "_id": { - "type": "string" - }, - "key": { - "type": "string" - }, - "remark": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "routes.SpiderFileReqBody": { - "type": "object", - "properties": { - "content": { - "type": "string" - }, - "new_path": { - "type": "string" - }, - "path": { - "type": "string" - } - } - }, - "routes.TaskListRequestData": { - "type": "object", - "properties": { - "nodeId": { - "type": "string" - }, - "pageNum": { - "type": "integer" - }, - "pageSize": { - "type": "integer" - }, - "scheduleId": { - "type": "string" - }, - "spiderId": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, - "routes.TaskResultsRequestData": { - "type": "object", - "properties": { - "pageNum": { - "type": "integer" - }, - "pageSize": { - "type": "integer" - } - } - }, - "routes.UserListRequestData": { - "type": "object", - "properties": { - "pageNum": { - "type": "integer" - }, - "pageSize": { - "type": "integer" - } - } - }, - "routes.UserRequestData": { - "type": "object", - "properties": { - "email": { - "type": "string" - }, - "password": { - "type": "string" - }, - "role": { - "type": "string" - }, - "username": { - "type": "string" - } - } - } - } -} \ No newline at end of file diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml deleted file mode 100644 index 26598b52..00000000 --- a/backend/docs/swagger.yaml +++ /dev/null @@ -1,3177 +0,0 @@ -definitions: - entity.ConfigSpiderData: - properties: - cmd: - description: 自定义爬虫 - type: string - col: - type: string - display_name: - type: string - engine: - description: 可配置爬虫 - type: string - name: - description: 通用 - type: string - remark: - type: string - settings: - type: object - stages: - items: - $ref: '#/definitions/entity.Stage' - type: array - start_stage: - type: string - start_url: - type: string - type: - type: string - type: object - entity.Field: - properties: - attr: - type: string - css: - type: string - name: - type: string - next_stage: - type: string - remark: - type: string - xpath: - type: string - type: object - entity.ScrapyItem: - properties: - fields: - items: - type: string - type: array - name: - type: string - type: object - entity.ScrapySettingParam: - properties: - key: - type: string - type: - type: string - value: - type: object - type: object - entity.Stage: - properties: - fields: - items: - $ref: '#/definitions/entity.Field' - type: array - is_list: - type: boolean - list_css: - type: string - list_xpath: - type: string - name: - type: string - page_attr: - type: string - page_css: - type: string - page_xpath: - type: string - type: object - model.Env: - properties: - name: - type: string - value: - type: string - type: object - model.Node: - properties: - _id: - type: string - create_ts: - type: string - description: - type: string - hostname: - type: string - ip: - type: string - is_master: - description: 前端展示 - type: boolean - key: - description: 用于唯一标识节点,可能是mac地址,可能是ip地址 - type: string - mac: - type: string - name: - type: string - port: - type: string - status: - type: string - update_ts: - type: string - update_ts_unix: - type: integer - type: object - model.Project: - properties: - _id: - type: string - create_ts: - type: string - description: - type: string - name: - type: string - spiders: - description: 前端展示 - items: - $ref: '#/definitions/model.Spider' - type: array - tags: - items: - type: string - type: array - update_ts: - type: string - user_id: - type: string - username: - type: string - type: object - model.Schedule: - properties: - _id: - type: string - create_ts: - type: string - cron: - type: string - description: - type: string - enabled: - type: boolean - entry_id: - type: integer - message: - type: string - name: - type: string - node_ids: - items: - type: string - type: array - nodes: - items: - $ref: '#/definitions/model.Node' - type: array - param: - type: string - run_type: - type: string - scrapy_log_level: - type: string - scrapy_spider: - type: string - spider_id: - type: string - spider_name: - description: 前端展示 - type: string - status: - type: string - update_ts: - type: string - user_id: - type: string - user_name: - type: string - type: object - model.Spider: - properties: - _id: - description: 爬虫ID - type: string - cmd: - description: 自定义爬虫 - type: string - col: - description: 结果储存位置 - type: string - config: - $ref: '#/definitions/entity.ConfigSpiderData' - description: 可配置爬虫配置 - type: object - create_ts: - type: string - dedup_field: - description: 去重字段 - type: string - dedup_method: - description: 去重方式 - type: string - display_name: - description: 爬虫显示名称 - type: string - envs: - description: 环境变量 - items: - $ref: '#/definitions/model.Env' - type: array - file_id: - description: GridFS文件ID - type: string - git_auto_sync: - description: Git 是否自动同步 - type: boolean - git_branch: - description: Git 分支 - type: string - git_has_credential: - description: Git 是否加密 - type: boolean - git_password: - description: Git 密码 - type: string - git_sync_error: - description: Git 同步错误 - type: string - git_sync_frequency: - description: Git 同步频率 - type: string - git_url: - description: Git URL - type: string - git_username: - description: Git 用户名 - type: string - is_dedup: - description: 去重 - type: boolean - is_git: - description: Git 设置 - type: boolean - is_long_task: - description: 长任务 - type: boolean - is_public: - description: 是否公开 - type: boolean - is_scrapy: - description: Scrapy 爬虫(属于自定义爬虫) - type: boolean - is_web_hook: - description: Web Hook - type: boolean - last_run_ts: - description: 前端展示 - type: string - last_status: - description: 最后执行状态 - type: string - latest_tasks: - description: 最近任务列表 - items: - $ref: '#/definitions/model.Task' - type: array - name: - description: 爬虫名称(唯一) - type: string - project_id: - description: 项目ID - type: string - remark: - description: 备注 - type: string - site: - description: 爬虫网站 - type: string - spider_names: - description: 爬虫名称列表 - items: - type: string - type: array - src: - description: 源码位置 - type: string - template: - description: 可配置爬虫 - type: string - type: - description: 爬虫类别 - type: string - update_ts: - type: string - user_id: - description: 时间 - type: string - username: - description: 用户名称 - type: string - web_hook_url: - description: Web Hook URL - type: string - type: object - model.Task: - properties: - _id: - type: string - cmd: - type: string - create_ts: - type: string - error: - type: string - error_log_count: - type: integer - finish_ts: - type: string - log_path: - type: string - node_id: - type: string - node_name: - type: string - param: - type: string - pid: - type: integer - result_count: - type: integer - run_type: - type: string - runtime_duration: - type: number - schedule_id: - type: string - spider_id: - type: string - spider_name: - description: 前端数据 - type: string - start_ts: - type: string - status: - type: string - total_duration: - type: number - update_ts: - type: string - user_id: - type: string - username: - type: string - wait_duration: - type: number - type: object - model.User: - properties: - _id: - type: string - create_ts: - type: string - email: - type: string - password: - type: string - role: - type: string - setting: - $ref: '#/definitions/model.UserSetting' - type: object - update_ts: - type: string - user_id: - type: string - username: - type: string - type: object - model.UserSetting: - properties: - ding_talk_robot_webhook: - type: string - enabled_notifications: - items: - type: string - type: array - error_regex_pattern: - type: string - log_expire_duration: - type: integer - max_error_log: - type: integer - notification_trigger: - type: string - wechat_robot_webhook: - type: string - type: object - model.Variable: - properties: - _id: - type: string - key: - type: string - remark: - type: string - value: - type: string - type: object - routes.SpiderFileReqBody: - properties: - content: - type: string - new_path: - type: string - path: - type: string - type: object - routes.TaskListRequestData: - properties: - nodeId: - type: string - pageNum: - type: integer - pageSize: - type: integer - scheduleId: - type: string - spiderId: - type: string - status: - type: string - type: object - routes.TaskResultsRequestData: - properties: - pageNum: - type: integer - pageSize: - type: integer - type: object - routes.UserListRequestData: - properties: - pageNum: - type: integer - pageSize: - type: integer - type: object - routes.UserRequestData: - properties: - email: - type: string - password: - type: string - role: - type: string - username: - type: string - type: object -info: - contact: {} - license: {} -paths: - /config_spiders: - put: - consumes: - - application/json - description: Put config spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider item - in: body - name: spider - required: true - schema: - $ref: '#/definitions/model.Spider' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Put config spider - tags: - - config spider - /config_spiders/{id}/config: - get: - consumes: - - application/json - description: Get config spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Get config spider - tags: - - config spider - post: - consumes: - - application/json - description: Post config spider config - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider item - in: body - name: spider - required: true - schema: - $ref: '#/definitions/model.Spider' - type: object - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Post config spider config - tags: - - config spider - /config_spiders/{id}/spiderfile: - post: - consumes: - - application/json - description: Post config spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Post config spider - tags: - - config spider - /config_spiders/{id}/upload: - post: - consumes: - - application/json - description: Upload config spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider item - in: body - name: spider - required: true - schema: - $ref: '#/definitions/model.Spider' - type: object - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Upload config spider - tags: - - config spider - /config_spiders_templates: - get: - consumes: - - application/json - description: Get config spider template list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Get config spider template list - tags: - - config spider - /docs: - get: - description: Get docs - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get docs - tags: - - docs - /file: - get: - description: Get file - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get file - tags: - - file - /nodes: - get: - description: Get nodes - parameters: - - description: With the bearer started - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get nodes - tags: - - node - /nodes/{id}: - delete: - description: Delete node - parameters: - - description: With the bearer started - in: header - name: Authorization - required: true - type: string - - description: node id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete node - tags: - - node - get: - description: Get node - parameters: - - description: With the bearer started - in: header - name: Authorization - required: true - type: string - - description: id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get node - tags: - - node - post: - consumes: - - application/json - description: Post node - parameters: - - description: With the bearer started - in: header - name: Authorization - required: true - type: string - - description: post node - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Post node - tags: - - node - /nodes/{id}/deps: - get: - description: Get dep list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: node id - in: path - name: id - required: true - type: string - - description: language - in: query - name: lang - required: true - type: string - - description: dep name - in: query - name: dep_name - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get dep list - tags: - - system - /nodes/{id}/deps/install: - post: - description: Install dep - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: node id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Install dep - tags: - - system - /nodes/{id}/deps/installed: - get: - description: Get installed dep list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: node id - in: path - name: id - required: true - type: string - - description: language - in: query - name: lang - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get installed dep list - tags: - - system - /nodes/{id}/deps/uninstall: - post: - description: Uninstall dep - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: node id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Uninstall dep - tags: - - system - /nodes/{id}/langs: - get: - description: Get language list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: node id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get language list - tags: - - system - /nodes/{id}/langs/install: - post: - description: Install language - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: node id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Install language - tags: - - system - /nodes/{id}/system: - get: - description: Get system info - parameters: - - description: With the bearer started - in: header - name: Authorization - required: true - type: string - - description: node id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get system info - tags: - - node - /nodes/{id}/tasks: - get: - description: Get tasks on node - parameters: - - description: With the bearer started - in: header - name: Authorization - required: true - type: string - - description: node id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get tasks on node - tags: - - node - /projects: - get: - description: Get projects - parameters: - - description: With the bearer started - in: header - name: Authorization - required: true - type: string - - description: projects - in: query - name: tag - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get projects - tags: - - project - put: - consumes: - - application/json - description: Put project - parameters: - - description: With the bearer started - in: header - name: Authorization - required: true - type: string - - description: post project - in: body - name: p - required: true - schema: - $ref: '#/definitions/model.Project' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Put project - tags: - - project - /projects/{id}: - delete: - description: Delete project - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: project id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete project - tags: - - project - post: - consumes: - - application/json - description: Post project - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: project id - in: path - name: id - required: true - type: string - - description: project item - in: body - name: item - required: true - schema: - $ref: '#/definitions/model.Project' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Post project - tags: - - project - /projects/tags: - get: - description: Get projects tags - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get project tags - tags: - - project - /releases/latest: - get: - description: Get latest release - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get latest release - tags: - - version - /schedules: - get: - description: Get spider list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: page num - in: query - name: page_num - type: string - - description: page size - in: query - name: page_size - type: string - - description: keyword - in: query - name: keyword - type: string - - description: project_id - in: query - name: project_id - type: string - - description: type - in: query - name: type - type: string - - description: sort_key - in: query - name: sort_key - type: string - - description: sort_direction - in: query - name: sort_direction - type: string - - description: owner_type - in: query - name: owner_type - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get spider list - tags: - - spider - put: - consumes: - - application/json - description: Put schedule - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule item - in: body - name: item - required: true - schema: - $ref: '#/definitions/model.Schedule' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Put schedule - tags: - - schedule - /schedules/{id}: - delete: - description: Delete schedule - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete schedule - tags: - - schedule - get: - description: Get schedule by id - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get schedule by id - tags: - - schedule - post: - consumes: - - application/json - description: Post schedule - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule id - in: path - name: id - required: true - type: string - - description: schedule item - in: body - name: newItem - required: true - schema: - $ref: '#/definitions/model.Schedule' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Post schedule - tags: - - schedule - /schedules/{id}/disable: - post: - consumes: - - application/json - description: disable schedule - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: disable schedule - tags: - - schedule - /schedules/{id}/enable: - post: - consumes: - - application/json - description: enable schedule - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: enable schedule - tags: - - schedule - /setting: - get: - description: Get setting - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get setting - tags: - - setting - /spiders: - post: - consumes: - - application/json - description: delete spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: delete spider - tags: - - spider - put: - consumes: - - application/json - description: Put spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider item - in: body - name: spider - required: true - schema: - $ref: '#/definitions/model.Spider' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Put spider - tags: - - spider - /spiders-cancel: - post: - consumes: - - application/json - description: cancel spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: cancel spider - tags: - - spider - /spiders-run: - post: - consumes: - - application/json - description: run spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: run spider - tags: - - spider - /spiders/{id}: - delete: - description: Delete spider by id - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete spider by id - tags: - - spider - get: - description: Get spider by id - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get spider by id - tags: - - spider - post: - consumes: - - application/json - description: Post spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule id - in: path - name: id - required: true - type: string - - description: spider item - in: body - name: item - required: true - schema: - $ref: '#/definitions/model.Spider' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Post spider - tags: - - spider - /spiders/{id}/copy: - post: - consumes: - - application/json - description: Copy spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Copy spider - tags: - - spider - /spiders/{id}/dir: - get: - description: Get spider dir - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - - description: path - in: query - name: path - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get spider dir - tags: - - spider - /spiders/{id}/file: - delete: - description: Delete spider file - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - - description: path - in: body - name: reqBody - required: true - schema: - $ref: '#/definitions/routes.SpiderFileReqBody' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete spider file - tags: - - spider - get: - description: Get spider file - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - - description: path - in: query - name: path - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get spider file - tags: - - spider - post: - description: Put spider file - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - - description: path - in: body - name: reqBody - required: true - schema: - $ref: '#/definitions/routes.SpiderFileReqBody' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Put spider file - tags: - - spider - put: - description: Post spider dir - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - - description: path - in: body - name: reqBody - required: true - schema: - $ref: '#/definitions/routes.SpiderFileReqBody' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Post spider dir - tags: - - spider - /spiders/{id}/file/rename: - post: - description: Rename spider file - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - - description: path - in: body - name: reqBody - required: true - schema: - $ref: '#/definitions/routes.SpiderFileReqBody' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Rename spider file - tags: - - spider - /spiders/{id}/file/tree: - get: - description: Get spider dir - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get spider dir - tags: - - spider - /spiders/{id}/git/reset: - post: - description: Post spider reset git - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Post spider reset git - tags: - - spider - /spiders/{id}/git/sync: - post: - description: Post spider sync git - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Post spider sync git - tags: - - spider - /spiders/{id}/publish: - post: - consumes: - - application/json - description: Publish spider - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: schedule id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Publish spider - tags: - - spider - /spiders/{id}/schedules: - get: - description: Get schedules - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get schedules - tags: - - spider - /spiders/{id}/scrapy/items: - get: - description: Get scrapy spider items - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get scrapy spider items - tags: - - spider - post: - description: Post scrapy spider items - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - - description: req data - in: body - name: reqData - required: true - schema: - items: - $ref: '#/definitions/entity.ScrapyItem' - type: entity.ScrapyItem - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Post scrapy spider items - tags: - - spider - /spiders/{id}/scrapy/pipelines: - get: - description: Get scrapy spider pipelines - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get scrapy spider pipelines - tags: - - spider - /spiders/{id}/scrapy/settings: - get: - description: Get scrapy spider settings - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get scrapy spider settings - tags: - - spider - post: - description: Get scrapy spider file - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - - description: req data - in: body - name: reqData - required: true - schema: - items: - $ref: '#/definitions/entity.ScrapySettingParam' - type: entity.ScrapySettingParam - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get scrapy spider file - tags: - - spider - /spiders/{id}/scrapy/spider/filepath: - get: - description: Get scrapy spider file path - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get scrapy spider file path - tags: - - spider - /spiders/{id}/scrapy/spiders: - get: - description: Get scrapy spider file - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get scrapy spider file - tags: - - spider - put: - description: Put scrapy spider file - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Put scrapy spider file - tags: - - spider - /spiders/{id}/stats: - get: - description: Get spider stats - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get spider stats - tags: - - spider - /spiders/{id}/tasks: - get: - description: Get task list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get task list - tags: - - spider - /spiders/{id}/upload: - post: - consumes: - - application/json - description: Upload spider by id - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: spider file to upload - in: formData - name: file - required: true - type: file - - description: spider id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "500": - description: Internal Server Error - schema: - type: json - summary: Upload spider by id - tags: - - spider - /stats/home: - get: - description: Get home stats - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get home stats - tags: - - version - /system/deps/: - get: - description: Get all dep list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: language - in: path - name: lang - required: true - type: string - - description: dep name - in: query - name: dep_nane - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get all dep list - tags: - - system - /system/deps/{lang}/{dep_name}/json: - get: - description: Get dep json - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: language - in: path - name: lang - required: true - type: string - - description: dep name - in: path - name: dep_name - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get dep json - tags: - - system - /task/{id}: - delete: - description: Delete task - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: task id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete task - tags: - - task - /tasks: - delete: - description: Delete tasks - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete tasks - tags: - - task - get: - description: Get task list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: req data - in: body - name: data - required: true - schema: - $ref: '#/definitions/routes.TaskListRequestData' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get task list - tags: - - task - put: - description: Put task - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Put task - tags: - - task - /tasks/{id}: - get: - description: Get task - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: task id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get task - tags: - - task - /tasks/{id}/cancel: - post: - description: Cancel task - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: task id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Cancel task - tags: - - task - /tasks/{id}/error-log: - delete: - description: Get task error log - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: task id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get task error log - tags: - - task - /tasks/{id}/log: - delete: - description: Get task log - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: task id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get task log - tags: - - task - /tasks/{id}/restart: - post: - description: Restart task - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: task id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Restart task - tags: - - task - /tasks/{id}/results: - get: - description: Get task list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: req data - in: body - name: data - required: true - schema: - $ref: '#/definitions/routes.TaskResultsRequestData' - type: object - - description: task id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get task list - tags: - - task - /tasks/{id}/results/download: - get: - description: Get task results - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: task id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get task results - tags: - - task - /tasks_by_status: - delete: - description: Delete task - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: task status - in: query - name: status - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete task - tags: - - task - /tokens: - get: - description: token - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get token - tags: - - token - put: - description: token - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Put token - tags: - - token - /tokens/{id}: - delete: - description: Delete token - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: token id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete token - tags: - - token - /users: - get: - description: Get user list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: data body - in: body - name: data - required: true - schema: - $ref: '#/definitions/routes.UserListRequestData' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get user list - tags: - - token - put: - description: Put user - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: reqData body - in: body - name: reqData - required: true - schema: - $ref: '#/definitions/routes.UserRequestData' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Put user - tags: - - user - /users/{id}: - delete: - description: Delete user - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: user id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete user - tags: - - user - get: - description: user - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: user id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get user - tags: - - user - post: - description: Post user - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: user body - in: body - name: item - required: true - schema: - $ref: '#/definitions/model.User' - type: object - - description: user id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Post user - tags: - - user - /variable: - put: - description: Put variable - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: reqData body - in: body - name: variable - required: true - schema: - $ref: '#/definitions/model.Variable' - type: object - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Put variable - tags: - - variable - /variable/{id}: - delete: - description: Delete variable - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: variable id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Delete variable - tags: - - variable - post: - description: Post variable - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - - description: reqData body - in: body - name: variable - required: true - schema: - $ref: '#/definitions/model.Variable' - type: object - - description: variable id - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Post variable - tags: - - variable - /variables: - get: - description: Get variable list - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get variable list - tags: - - variable - /version: - get: - description: Get version - parameters: - - description: Authorization token - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - type: json - "400": - description: Bad Request - schema: - type: json - summary: Get version - tags: - - setting -swagger: "2.0" diff --git a/backend/dump.rdb b/backend/dump.rdb deleted file mode 100644 index 6f8d62d29bd347cf8cb196b5852bbd9f5961fec1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155 zcmWG?b@2=~FfcIt$H2mxm!Fba%qW;>Vr80YWoBTNVq}$MX_b=XkX@~mo0zO*rGz1+ zq@$Es0F*E^H_|gQ&@(j9GXe_bCKi{Z7AaYk6qTmxD3unZB$lMcmlOll85tN_>Kd5q o8X1Kc8d(_|S{a$@85kIuSr}^@SXdbtDAoSA{lxkEoA|$T0MiRBZvX%Q diff --git a/backend/entity/common.go b/backend/entity/common.go deleted file mode 100644 index c46ae4f9..00000000 --- a/backend/entity/common.go +++ /dev/null @@ -1,17 +0,0 @@ -package entity - -import "strconv" - -type Page struct { - Skip int - Limit int - PageNum int - PageSize int -} - -func (p *Page) GetPage(pageNum string, pageSize string) { - p.PageNum, _ = strconv.Atoi(pageNum) - p.PageSize, _ = strconv.Atoi(pageSize) - p.Skip = p.PageSize * (p.PageNum - 1) - p.Limit = p.PageSize -} diff --git a/backend/entity/config_spider.go b/backend/entity/config_spider.go deleted file mode 100644 index 054ee2fe..00000000 --- a/backend/entity/config_spider.go +++ /dev/null @@ -1,40 +0,0 @@ -package entity - -type ConfigSpiderData struct { - // 通用 - Name string `yaml:"name" json:"name"` - DisplayName string `yaml:"display_name" json:"display_name"` - Col string `yaml:"col" json:"col"` - Remark string `yaml:"remark" json:"remark"` - Type string `yaml:"type" bson:"type"` - - // 可配置爬虫 - Engine string `yaml:"engine" json:"engine"` - StartUrl string `yaml:"start_url" json:"start_url"` - StartStage string `yaml:"start_stage" json:"start_stage"` - Stages []Stage `yaml:"stages" json:"stages"` - Settings map[string]string `yaml:"settings" json:"settings"` - - // 自定义爬虫 - Cmd string `yaml:"cmd" json:"cmd"` -} - -type Stage struct { - Name string `yaml:"name" json:"name"` - IsList bool `yaml:"is_list" json:"is_list"` - ListCss string `yaml:"list_css" json:"list_css"` - ListXpath string `yaml:"list_xpath" json:"list_xpath"` - PageCss string `yaml:"page_css" json:"page_css"` - PageXpath string `yaml:"page_xpath" json:"page_xpath"` - PageAttr string `yaml:"page_attr" json:"page_attr"` - Fields []Field `yaml:"fields" json:"fields"` -} - -type Field struct { - Name string `yaml:"name" json:"name"` - Css string `yaml:"css" json:"css"` - Xpath string `yaml:"xpath" json:"xpath"` - Attr string `yaml:"attr" json:"attr"` - NextStage string `yaml:"next_stage" json:"next_stage"` - Remark string `yaml:"remark" json:"remark"` -} diff --git a/backend/entity/doc.go b/backend/entity/doc.go deleted file mode 100644 index b356d38a..00000000 --- a/backend/entity/doc.go +++ /dev/null @@ -1,8 +0,0 @@ -package entity - -type DocItem struct { - Title string `json:"title"` - Url string `json:"url"` - Path string `json:"path"` - Children []DocItem `json:"children"` -} diff --git a/backend/entity/node.go b/backend/entity/node.go deleted file mode 100644 index ebe2047f..00000000 --- a/backend/entity/node.go +++ /dev/null @@ -1,28 +0,0 @@ -package entity - -type NodeMessage struct { - // 通信类别 - Type string `json:"type"` - - // 任务相关 - TaskId string `json:"task_id"` // 任务ID - - // 节点相关 - NodeId string `json:"node_id"` // 节点ID - - // 日志相关 - LogPath string `json:"log_path"` // 日志路径 - Log string `json:"log"` // 日志 - - // 系统信息 - SysInfo SystemInfo `json:"sys_info"` - - // 爬虫相关 - SpiderId string `json:"spider_id"` //爬虫ID - - // 语言相关 - Lang Lang `json:"lang"` - - // 错误相关 - Error string `json:"error"` -} diff --git a/backend/entity/rpc.go b/backend/entity/rpc.go deleted file mode 100644 index 48f14b26..00000000 --- a/backend/entity/rpc.go +++ /dev/null @@ -1,11 +0,0 @@ -package entity - -type RpcMessage struct { - Id string `json:"id"` // 消息ID - Method string `json:"method"` // 消息方法 - NodeId string `json:"node_id"` // 节点ID - Params map[string]string `json:"params"` // 参数 - Timeout int `json:"timeout"` // 超时 - Result string `json:"result"` // 结果 - Error string `json:"error"` // 错误 -} diff --git a/backend/entity/spider.go b/backend/entity/spider.go deleted file mode 100644 index 616d3bbf..00000000 --- a/backend/entity/spider.go +++ /dev/null @@ -1,17 +0,0 @@ -package entity - -type SpiderType struct { - Type string `json:"type" bson:"_id"` - Count int `json:"count" bson:"count"` -} - -type ScrapySettingParam struct { - Key string `json:"key"` - Value interface{} `json:"value"` - Type string `json:"type"` -} - -type ScrapyItem struct { - Name string `json:"name"` - Fields []string `json:"fields"` -} diff --git a/backend/entity/system.go b/backend/entity/system.go deleted file mode 100644 index f1a24f4b..00000000 --- a/backend/entity/system.go +++ /dev/null @@ -1,39 +0,0 @@ -package entity - -type SystemInfo struct { - ARCH string `json:"arch"` - OS string `json:"os"` - Hostname string `json:"host_name"` - NumCpu int `json:"num_cpu"` - Executables []Executable `json:"executables"` -} - -type Executable struct { - Path string `json:"path"` - FileName string `json:"file_name"` - DisplayName string `json:"display_name"` -} - -type Lang struct { - Name string `json:"name"` - ExecutableName string `json:"executable_name"` - ExecutablePaths []string `json:"executable_paths"` - DepExecutablePath string `json:"dep_executable_path"` - LockPath string `json:"lock_path"` - InstallScript string `json:"install_script"` - InstallStatus string `json:"install_status"` - DepFileName string `json:"dep_file_name"` - InstallDepArgs string `json:"install_dep_cmd"` - Type string `json:"type"` -} - -type Dependency struct { - Name string `json:"name"` - Version string `json:"version"` - Description string `json:"description"` - Installed bool `json:"installed"` -} - -type PackageJson struct { - Dependencies map[string]string `json:"dependencies"` -} diff --git a/backend/entity/version.go b/backend/entity/version.go deleted file mode 100644 index 97a0278d..00000000 --- a/backend/entity/version.go +++ /dev/null @@ -1,23 +0,0 @@ -package entity - -type Release struct { - Name string `json:"name"` - Draft bool `json:"draft"` - PreRelease bool `json:"pre_release"` - PublishedAt string `json:"published_at"` - Body string `json:"body"` -} - -type ReleaseSlices []Release - -func (r ReleaseSlices) Len() int { - return len(r) -} - -func (r ReleaseSlices) Less(i, j int) bool { - return r[i].PublishedAt < r[j].PublishedAt -} - -func (r ReleaseSlices) Swap(i, j int) { - r[i], r[j] = r[j], r[i] -} diff --git a/backend/errors/errors.go b/backend/errors/errors.go deleted file mode 100644 index d896e4d4..00000000 --- a/backend/errors/errors.go +++ /dev/null @@ -1,54 +0,0 @@ -package errors - -import ( - "fmt" - "net/http" -) - -type Scope int - -const ( - ScopeSystem Scope = 1 - ScopeBusiness Scope = 2 -) - -type OPError struct { - HttpCode int - Message string - Code int - Scope Scope -} - -func (O OPError) Error() string { - var scope string - switch O.Scope { - case ScopeSystem: - scope = "system" - case ScopeBusiness: - scope = "business" - } - return fmt.Sprintf("%s error: [%d]%s.", scope, O.Code, O.Message) -} - -func NewSystemOPError(code int, message string, httpCodes ...int) *OPError { - httpCode := http.StatusOK - if len(httpCodes) > 0 { - httpCode = httpCodes[0] - } - return NewOpError(code, message, ScopeSystem, httpCode) -} -func NewOpError(code int, message string, scope Scope, httpCode int) *OPError { - return &OPError{ - Message: message, - Code: code, - Scope: scope, - HttpCode: httpCode, - } -} -func NewBusinessError(code int, message string, httpCodes ...int) *OPError { - httpCode := http.StatusOK - if len(httpCodes) > 0 { - httpCode = httpCodes[0] - } - return NewOpError(code, message, ScopeBusiness, httpCode) -} diff --git a/backend/go.mod b/backend/go.mod index 3f1fda3a..6d2ab8d5 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -1,43 +1,47 @@ module crawlab -go 1.12 +go 1.15 + +replace ( + github.com/crawlab-team/crawlab-core => /Users/marvzhang/projects/crawlab-team/crawlab-core + github.com/crawlab-team/crawlab-db => /Users/marvzhang/projects/crawlab-team/crawlab-db +) require ( github.com/Masterminds/semver v1.4.2 // indirect github.com/Masterminds/sprig v2.16.0+incompatible // indirect - github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 + github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd // indirect github.com/aokoli/goutils v1.0.1 // indirect - github.com/apex/log v1.1.4 - github.com/cenkalti/backoff/v4 v4.0.2 - github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/fsnotify/fsnotify v1.4.9 + github.com/apex/log v1.9.0 + github.com/cenkalti/backoff/v4 v4.1.0 // indirect + github.com/crawlab-team/crawlab-core v0.0.0-00010101000000-000000000000 + github.com/crawlab-team/crawlab-db v0.0.2 + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/gin-gonic/gin v1.6.3 - github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 + github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 // indirect github.com/go-playground/validator/v10 v10.3.0 - github.com/gomodule/redigo v2.0.0+incompatible - github.com/hashicorp/go-sockaddr v1.0.0 + github.com/gomodule/redigo v2.0.0+incompatible // indirect + github.com/hashicorp/go-sockaddr v1.0.0 // indirect github.com/huandu/xstrings v1.2.0 // indirect github.com/imdario/mergo v0.3.6 // indirect - github.com/imroc/req v0.3.0 + github.com/imroc/req v0.3.0 // indirect github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 // indirect - github.com/matcornic/hermes v1.2.0 + github.com/matcornic/hermes v1.2.0 // indirect github.com/mattn/go-runewidth v0.0.3 // indirect github.com/olekukonko/tablewriter v0.0.1 // indirect github.com/olivere/elastic/v7 v7.0.15 - github.com/pkg/errors v0.9.1 - github.com/satori/go.uuid v1.2.0 - github.com/smartystreets/goconvey v1.6.4 - github.com/spf13/viper v1.7.0 + github.com/pkg/errors v0.9.1 // indirect + github.com/satori/go.uuid v1.2.0 // indirect + github.com/smartystreets/goconvey v1.6.4 // indirect + github.com/spf13/viper v1.7.1 github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect - github.com/swaggo/gin-swagger v1.2.0 - github.com/swaggo/swag v1.6.6 - go.uber.org/atomic v1.6.0 + go.uber.org/atomic v1.6.0 // indirect golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect - gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect gopkg.in/russross/blackfriday.v2 v2.0.0 // indirect - gopkg.in/src-d/go-git.v4 v4.13.1 - gopkg.in/yaml.v2 v2.3.0 + gopkg.in/src-d/go-git.v4 v4.13.1 // indirect + gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index c53a2aaf..5779ab97 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -42,7 +42,10 @@ github.com/aokoli/goutils v1.0.1 h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg= github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= github.com/apex/log v1.1.4 h1:3Zk+boorIQAAGBrHn0JUtAau4ihMamT4WdnfdnXM1zQ= github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= +github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= +github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= +github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -59,6 +62,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/cenkalti/backoff/v4 v4.0.2 h1:JIufpQLbh4DkbQoii76ItQIUFzevQSqOLZca4eamEDs= github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= +github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc= +github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -137,6 +142,7 @@ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o= github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -213,6 +219,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -232,6 +240,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= @@ -239,6 +248,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -261,6 +272,7 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= @@ -343,6 +355,8 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= @@ -356,6 +370,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= @@ -366,6 +381,8 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.6.6 h1:3YX5hmuUyCMT/OqqnjW92gULAfHg3hVjpcPm53N64RY= github.com/swaggo/swag v1.6.6/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= +github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= @@ -580,6 +597,8 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/backend/lib/cron/.gitignore b/backend/lib/cron/.gitignore deleted file mode 100644 index 00268614..00000000 --- a/backend/lib/cron/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/backend/lib/cron/.travis.yml b/backend/lib/cron/.travis.yml deleted file mode 100644 index 4f2ee4d9..00000000 --- a/backend/lib/cron/.travis.yml +++ /dev/null @@ -1 +0,0 @@ -language: go diff --git a/backend/lib/cron/LICENSE b/backend/lib/cron/LICENSE deleted file mode 100644 index 3a0f627f..00000000 --- a/backend/lib/cron/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (C) 2012 Rob Figueiredo -All Rights Reserved. - -MIT LICENSE - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/backend/lib/cron/README.md b/backend/lib/cron/README.md deleted file mode 100644 index 979f71e6..00000000 --- a/backend/lib/cron/README.md +++ /dev/null @@ -1,125 +0,0 @@ -[![GoDoc](http://godoc.org/github.com/robfig/cron?status.png)](http://godoc.org/github.com/robfig/cron) -[![Build Status](https://travis-ci.org/robfig/cron.svg?branch=master)](https://travis-ci.org/robfig/cron) - -# cron - -Cron V3 has been released! - -To download the specific tagged release, run: - - go get github.com/robfig/cron/v3@v3.0.0 - -Import it in your program as: - - import "github.com/robfig/cron/v3" - -It requires Go 1.11 or later due to usage of Go Modules. - -Refer to the documentation here: -http://godoc.org/github.com/robfig/cron - -The rest of this document describes the the advances in v3 and a list of -breaking changes for users that wish to upgrade from an earlier version. - -## Upgrading to v3 (June 2019) - -cron v3 is a major upgrade to the library that addresses all outstanding bugs, -feature requests, and rough edges. It is based on a merge of master which -contains various fixes to issues found over the years and the v2 branch which -contains some backwards-incompatible features like the ability to remove cron -jobs. In addition, v3 adds support for Go Modules, cleans up rough edges like -the timezone support, and fixes a number of bugs. - -New features: - -- Support for Go modules. Callers must now import this library as - `github.com/robfig/cron/v3`, instead of `gopkg.in/...` - -- Fixed bugs: - - 0f01e6b parser: fix combining of Dow and Dom (#70) - - dbf3220 adjust times when rolling the clock forward to handle non-existent midnight (#157) - - eeecf15 spec_test.go: ensure an error is returned on 0 increment (#144) - - 70971dc cron.Entries(): update request for snapshot to include a reply channel (#97) - - 1cba5e6 cron: fix: removing a job causes the next scheduled job to run too late (#206) - -- Standard cron spec parsing by default (first field is "minute"), with an easy - way to opt into the seconds field (quartz-compatible). Although, note that the - year field (optional in Quartz) is not supported. - -- Extensible, key/value logging via an interface that complies with - the https://github.com/go-logr/logr project. - -- The new Chain & JobWrapper types allow you to install "interceptors" to add - cross-cutting behavior like the following: - - Recover any panics from jobs - - Delay a job's execution if the previous run hasn't completed yet - - Skip a job's execution if the previous run hasn't completed yet - - Log each job's invocations - - Notification when jobs are completed - -It is backwards incompatible with both v1 and v2. These updates are required: - -- The v1 branch accepted an optional seconds field at the beginning of the cron - spec. This is non-standard and has led to a lot of confusion. The new default - parser conforms to the standard as described by [the Cron wikipedia page]. - - UPDATING: To retain the old behavior, construct your Cron with a custom - parser: - - // Seconds field, required - cron.New(cron.WithSeconds()) - - // Seconds field, optional - cron.New( - cron.WithParser( - cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)) - -- The Cron type now accepts functional options on construction rather than the - previous ad-hoc behavior modification mechanisms (setting a field, calling a setter). - - UPDATING: Code that sets Cron.ErrorLogger or calls Cron.SetLocation must be - updated to provide those values on construction. - -- CRON_TZ is now the recommended way to specify the timezone of a single - schedule, which is sanctioned by the specification. The legacy "TZ=" prefix - will continue to be supported since it is unambiguous and easy to do so. - - UPDATING: No update is required. - -- By default, cron will no longer recover panics in jobs that it runs. - Recovering can be surprising (see issue #192) and seems to be at odds with - typical behavior of libraries. Relatedly, the `cron.WithPanicLogger` option - has been removed to accommodate the more general JobWrapper type. - - UPDATING: To opt into panic recovery and configure the panic logger: - - cron.New(cron.WithChain( - cron.Recover(logger), // or use cron.DefaultLogger - )) - -- In adding support for https://github.com/go-logr/logr, `cron.WithVerboseLogger` was - removed, since it is duplicative with the leveled logging. - - UPDATING: Callers should use `WithLogger` and specify a logger that does not - discard `Info` logs. For convenience, one is provided that wraps `*log.Logger`: - - cron.New( - cron.WithLogger(cron.VerbosePrintfLogger(logger))) - - -### Background - Cron spec format - -There are two cron spec formats in common usage: - -- The "standard" cron format, described on [the Cron wikipedia page] and used by - the cron Linux system utility. - -- The cron format used by [the Quartz Scheduler], commonly used for scheduled - jobs in Java software - -[the Cron wikipedia page]: https://en.wikipedia.org/wiki/Cron -[the Quartz Scheduler]: http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html - -The original version of this package included an optional "seconds" field, which -made it incompatible with both of these formats. Now, the "standard" format is -the default format accepted, and the Quartz format is opt-in. diff --git a/backend/lib/cron/chain.go b/backend/lib/cron/chain.go deleted file mode 100644 index 118e5bbe..00000000 --- a/backend/lib/cron/chain.go +++ /dev/null @@ -1,92 +0,0 @@ -package cron - -import ( - "fmt" - "runtime" - "sync" - "time" -) - -// JobWrapper decorates the given Job with some behavior. -type JobWrapper func(Job) Job - -// Chain is a sequence of JobWrappers that decorates submitted jobs with -// cross-cutting behaviors like logging or synchronization. -type Chain struct { - wrappers []JobWrapper -} - -// NewChain returns a Chain consisting of the given JobWrappers. -func NewChain(c ...JobWrapper) Chain { - return Chain{c} -} - -// Then decorates the given job with all JobWrappers in the chain. -// -// This: -// NewChain(m1, m2, m3).Then(job) -// is equivalent to: -// m1(m2(m3(job))) -func (c Chain) Then(j Job) Job { - for i := range c.wrappers { - j = c.wrappers[len(c.wrappers)-i-1](j) - } - return j -} - -// Recover panics in wrapped jobs and log them with the provided logger. -func Recover(logger Logger) JobWrapper { - return func(j Job) Job { - return FuncJob(func() { - defer func() { - if r := recover(); r != nil { - const size = 64 << 10 - buf := make([]byte, size) - buf = buf[:runtime.Stack(buf, false)] - err, ok := r.(error) - if !ok { - err = fmt.Errorf("%v", r) - } - logger.Error(err, "panic", "stack", "...\n"+string(buf)) - } - }() - j.Run() - }) - } -} - -// DelayIfStillRunning serializes jobs, delaying subsequent runs until the -// previous one is complete. Jobs running after a delay of more than a minute -// have the delay logged at Info. -func DelayIfStillRunning(logger Logger) JobWrapper { - return func(j Job) Job { - var mu sync.Mutex - return FuncJob(func() { - start := time.Now() - mu.Lock() - defer mu.Unlock() - if dur := time.Since(start); dur > time.Minute { - logger.Info("delay", "duration", dur) - } - j.Run() - }) - } -} - -// SkipIfStillRunning skips an invocation of the Job if a previous invocation is -// still running. It logs skips to the given logger at Info level. -func SkipIfStillRunning(logger Logger) JobWrapper { - var ch = make(chan struct{}, 1) - ch <- struct{}{} - return func(j Job) Job { - return FuncJob(func() { - select { - case v := <-ch: - j.Run() - ch <- v - default: - logger.Info("skip") - } - }) - } -} diff --git a/backend/lib/cron/chain_test.go b/backend/lib/cron/chain_test.go deleted file mode 100644 index 2561bd7f..00000000 --- a/backend/lib/cron/chain_test.go +++ /dev/null @@ -1,221 +0,0 @@ -package cron - -import ( - "io/ioutil" - "log" - "reflect" - "sync" - "testing" - "time" -) - -func appendingJob(slice *[]int, value int) Job { - var m sync.Mutex - return FuncJob(func() { - m.Lock() - *slice = append(*slice, value) - m.Unlock() - }) -} - -func appendingWrapper(slice *[]int, value int) JobWrapper { - return func(j Job) Job { - return FuncJob(func() { - appendingJob(slice, value).Run() - j.Run() - }) - } -} - -func TestChain(t *testing.T) { - var nums []int - var ( - append1 = appendingWrapper(&nums, 1) - append2 = appendingWrapper(&nums, 2) - append3 = appendingWrapper(&nums, 3) - append4 = appendingJob(&nums, 4) - ) - NewChain(append1, append2, append3).Then(append4).Run() - if !reflect.DeepEqual(nums, []int{1, 2, 3, 4}) { - t.Error("unexpected order of calls:", nums) - } -} - -func TestChainRecover(t *testing.T) { - panickingJob := FuncJob(func() { - panic("panickingJob panics") - }) - - t.Run("panic exits job by default", func(t *testing.T) { - defer func() { - if err := recover(); err == nil { - t.Errorf("panic expected, but none received") - } - }() - NewChain().Then(panickingJob). - Run() - }) - - t.Run("Recovering JobWrapper recovers", func(t *testing.T) { - NewChain(Recover(PrintfLogger(log.New(ioutil.Discard, "", 0)))). - Then(panickingJob). - Run() - }) - - t.Run("composed with the *IfStillRunning wrappers", func(t *testing.T) { - NewChain(Recover(PrintfLogger(log.New(ioutil.Discard, "", 0)))). - Then(panickingJob). - Run() - }) -} - -type countJob struct { - m sync.Mutex - started int - done int - delay time.Duration -} - -func (j *countJob) Run() { - j.m.Lock() - j.started++ - j.m.Unlock() - time.Sleep(j.delay) - j.m.Lock() - j.done++ - j.m.Unlock() -} - -func (j *countJob) Started() int { - defer j.m.Unlock() - j.m.Lock() - return j.started -} - -func (j *countJob) Done() int { - defer j.m.Unlock() - j.m.Lock() - return j.done -} - -func TestChainDelayIfStillRunning(t *testing.T) { - - t.Run("runs immediately", func(t *testing.T) { - var j countJob - wrappedJob := NewChain(DelayIfStillRunning(DiscardLogger)).Then(&j) - go wrappedJob.Run() - time.Sleep(2 * time.Millisecond) // Give the job 2ms to complete. - if c := j.Done(); c != 1 { - t.Errorf("expected job run once, immediately, got %d", c) - } - }) - - t.Run("second run immediate if first done", func(t *testing.T) { - var j countJob - wrappedJob := NewChain(DelayIfStillRunning(DiscardLogger)).Then(&j) - go func() { - go wrappedJob.Run() - time.Sleep(time.Millisecond) - go wrappedJob.Run() - }() - time.Sleep(3 * time.Millisecond) // Give both jobs 3ms to complete. - if c := j.Done(); c != 2 { - t.Errorf("expected job run twice, immediately, got %d", c) - } - }) - - t.Run("second run delayed if first not done", func(t *testing.T) { - var j countJob - j.delay = 10 * time.Millisecond - wrappedJob := NewChain(DelayIfStillRunning(DiscardLogger)).Then(&j) - go func() { - go wrappedJob.Run() - time.Sleep(time.Millisecond) - go wrappedJob.Run() - }() - - // After 5ms, the first job is still in progress, and the second job was - // run but should be waiting for it to finish. - time.Sleep(5 * time.Millisecond) - started, done := j.Started(), j.Done() - if started != 1 || done != 0 { - t.Error("expected first job started, but not finished, got", started, done) - } - - // Verify that the second job completes. - time.Sleep(25 * time.Millisecond) - started, done = j.Started(), j.Done() - if started != 2 || done != 2 { - t.Error("expected both jobs done, got", started, done) - } - }) - -} - -func TestChainSkipIfStillRunning(t *testing.T) { - - t.Run("runs immediately", func(t *testing.T) { - var j countJob - wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(&j) - go wrappedJob.Run() - time.Sleep(2 * time.Millisecond) // Give the job 2ms to complete. - if c := j.Done(); c != 1 { - t.Errorf("expected job run once, immediately, got %d", c) - } - }) - - t.Run("second run immediate if first done", func(t *testing.T) { - var j countJob - wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(&j) - go func() { - go wrappedJob.Run() - time.Sleep(time.Millisecond) - go wrappedJob.Run() - }() - time.Sleep(3 * time.Millisecond) // Give both jobs 3ms to complete. - if c := j.Done(); c != 2 { - t.Errorf("expected job run twice, immediately, got %d", c) - } - }) - - t.Run("second run skipped if first not done", func(t *testing.T) { - var j countJob - j.delay = 10 * time.Millisecond - wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(&j) - go func() { - go wrappedJob.Run() - time.Sleep(time.Millisecond) - go wrappedJob.Run() - }() - - // After 5ms, the first job is still in progress, and the second job was - // aleady skipped. - time.Sleep(5 * time.Millisecond) - started, done := j.Started(), j.Done() - if started != 1 || done != 0 { - t.Error("expected first job started, but not finished, got", started, done) - } - - // Verify that the first job completes and second does not run. - time.Sleep(25 * time.Millisecond) - started, done = j.Started(), j.Done() - if started != 1 || done != 1 { - t.Error("expected second job skipped, got", started, done) - } - }) - - t.Run("skip 10 jobs on rapid fire", func(t *testing.T) { - var j countJob - j.delay = 10 * time.Millisecond - wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(&j) - for i := 0; i < 11; i++ { - go wrappedJob.Run() - } - time.Sleep(200 * time.Millisecond) - done := j.Done() - if done != 1 { - t.Error("expected 1 jobs executed, 10 jobs dropped, got", done) - } - }) - -} diff --git a/backend/lib/cron/constantdelay.go b/backend/lib/cron/constantdelay.go deleted file mode 100644 index cd6e7b1b..00000000 --- a/backend/lib/cron/constantdelay.go +++ /dev/null @@ -1,27 +0,0 @@ -package cron - -import "time" - -// ConstantDelaySchedule represents a simple recurring duty cycle, e.g. "Every 5 minutes". -// It does not support jobs more frequent than once a second. -type ConstantDelaySchedule struct { - Delay time.Duration -} - -// Every returns a crontab Schedule that activates once every duration. -// Delays of less than a second are not supported (will round up to 1 second). -// Any fields less than a Second are truncated. -func Every(duration time.Duration) ConstantDelaySchedule { - if duration < time.Second { - duration = time.Second - } - return ConstantDelaySchedule{ - Delay: duration - time.Duration(duration.Nanoseconds())%time.Second, - } -} - -// Next returns the next time this should be run. -// This rounds so that the next activation time will be on the second. -func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time { - return t.Add(schedule.Delay - time.Duration(t.Nanosecond())*time.Nanosecond) -} diff --git a/backend/lib/cron/constantdelay_test.go b/backend/lib/cron/constantdelay_test.go deleted file mode 100644 index f43a58ad..00000000 --- a/backend/lib/cron/constantdelay_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package cron - -import ( - "testing" - "time" -) - -func TestConstantDelayNext(t *testing.T) { - tests := []struct { - time string - delay time.Duration - expected string - }{ - // Simple cases - {"Mon Jul 9 14:45 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"}, - {"Mon Jul 9 14:59 2012", 15 * time.Minute, "Mon Jul 9 15:14 2012"}, - {"Mon Jul 9 14:59:59 2012", 15 * time.Minute, "Mon Jul 9 15:14:59 2012"}, - - // Wrap around hours - {"Mon Jul 9 15:45 2012", 35 * time.Minute, "Mon Jul 9 16:20 2012"}, - - // Wrap around days - {"Mon Jul 9 23:46 2012", 14 * time.Minute, "Tue Jul 10 00:00 2012"}, - {"Mon Jul 9 23:45 2012", 35 * time.Minute, "Tue Jul 10 00:20 2012"}, - {"Mon Jul 9 23:35:51 2012", 44*time.Minute + 24*time.Second, "Tue Jul 10 00:20:15 2012"}, - {"Mon Jul 9 23:35:51 2012", 25*time.Hour + 44*time.Minute + 24*time.Second, "Thu Jul 11 01:20:15 2012"}, - - // Wrap around months - {"Mon Jul 9 23:35 2012", 91*24*time.Hour + 25*time.Minute, "Thu Oct 9 00:00 2012"}, - - // Wrap around minute, hour, day, month, and year - {"Mon Dec 31 23:59:45 2012", 15 * time.Second, "Tue Jan 1 00:00:00 2013"}, - - // Round to nearest second on the delay - {"Mon Jul 9 14:45 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"}, - - // Round up to 1 second if the duration is less. - {"Mon Jul 9 14:45:00 2012", 15 * time.Millisecond, "Mon Jul 9 14:45:01 2012"}, - - // Round to nearest second when calculating the next time. - {"Mon Jul 9 14:45:00.005 2012", 15 * time.Minute, "Mon Jul 9 15:00 2012"}, - - // Round to nearest second for both. - {"Mon Jul 9 14:45:00.005 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"}, - } - - for _, c := range tests { - actual := Every(c.delay).Next(getTime(c.time)) - expected := getTime(c.expected) - if actual != expected { - t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.delay, expected, actual) - } - } -} diff --git a/backend/lib/cron/cron.go b/backend/lib/cron/cron.go deleted file mode 100644 index f6e451db..00000000 --- a/backend/lib/cron/cron.go +++ /dev/null @@ -1,350 +0,0 @@ -package cron - -import ( - "context" - "sort" - "sync" - "time" -) - -// Cron keeps track of any number of entries, invoking the associated func as -// specified by the schedule. It may be started, stopped, and the entries may -// be inspected while running. -type Cron struct { - entries []*Entry - chain Chain - stop chan struct{} - add chan *Entry - remove chan EntryID - snapshot chan chan []Entry - running bool - logger Logger - runningMu sync.Mutex - location *time.Location - parser Parser - nextID EntryID - jobWaiter sync.WaitGroup -} - -// Job is an interface for submitted cron jobs. -type Job interface { - Run() -} - -// Schedule describes a job's duty cycle. -type Schedule interface { - // Next returns the next activation time, later than the given time. - // Next is invoked initially, and then each time the job is run. - Next(time.Time) time.Time -} - -// EntryID identifies an entry within a Cron instance -type EntryID int - -// Entry consists of a schedule and the func to execute on that schedule. -type Entry struct { - // ID is the cron-assigned ID of this entry, which may be used to look up a - // snapshot or remove it. - ID EntryID - - // Schedule on which this job should be run. - Schedule Schedule - - // Next time the job will run, or the zero time if Cron has not been - // started or this entry's schedule is unsatisfiable - Next time.Time - - // Prev is the last time this job was run, or the zero time if never. - Prev time.Time - - // WrappedJob is the thing to run when the Schedule is activated. - WrappedJob Job - - // Job is the thing that was submitted to cron. - // It is kept around so that user code that needs to get at the job later, - // e.g. via Entries() can do so. - Job Job -} - -// Valid returns true if this is not the zero entry. -func (e Entry) Valid() bool { return e.ID != 0 } - -// byTime is a wrapper for sorting the entry array by time -// (with zero time at the end). -type byTime []*Entry - -func (s byTime) Len() int { return len(s) } -func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s byTime) Less(i, j int) bool { - // Two zero times should return false. - // Otherwise, zero is "greater" than any other time. - // (To sort it at the end of the list.) - if s[i].Next.IsZero() { - return false - } - if s[j].Next.IsZero() { - return true - } - return s[i].Next.Before(s[j].Next) -} - -// New returns a new Cron job runner, modified by the given options. -// -// Available Settings -// -// Time Zone -// Description: The time zone in which schedules are interpreted -// Default: time.Local -// -// Parser -// Description: Parser converts cron spec strings into cron.Schedules. -// Default: Accepts this spec: https://en.wikipedia.org/wiki/Cron -// -// Chain -// Description: Wrap submitted jobs to customize behavior. -// Default: A chain that recovers panics and logs them to stderr. -// -// See "cron.With*" to modify the default behavior. -func New(opts ...Option) *Cron { - c := &Cron{ - entries: nil, - chain: NewChain(), - add: make(chan *Entry), - stop: make(chan struct{}), - snapshot: make(chan chan []Entry), - remove: make(chan EntryID), - running: false, - runningMu: sync.Mutex{}, - logger: DefaultLogger, - location: time.Local, - parser: standardParser, - } - for _, opt := range opts { - opt(c) - } - return c -} - -// FuncJob is a wrapper that turns a func() into a cron.Job -type FuncJob func() - -func (f FuncJob) Run() { f() } - -// AddFunc adds a func to the Cron to be run on the given schedule. -// The spec is parsed using the time zone of this Cron instance as the default. -// An opaque ID is returned that can be used to later remove it. -func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error) { - return c.AddJob(spec, FuncJob(cmd)) -} - -// AddJob adds a Job to the Cron to be run on the given schedule. -// The spec is parsed using the time zone of this Cron instance as the default. -// An opaque ID is returned that can be used to later remove it. -func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error) { - schedule, err := c.parser.Parse(spec) - if err != nil { - return 0, err - } - return c.Schedule(schedule, cmd), nil -} - -// Schedule adds a Job to the Cron to be run on the given schedule. -// The job is wrapped with the configured Chain. -func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID { - c.runningMu.Lock() - defer c.runningMu.Unlock() - c.nextID++ - entry := &Entry{ - ID: c.nextID, - Schedule: schedule, - WrappedJob: c.chain.Then(cmd), - Job: cmd, - } - if !c.running { - c.entries = append(c.entries, entry) - } else { - c.add <- entry - } - return entry.ID -} - -// Entries returns a snapshot of the cron entries. -func (c *Cron) Entries() []Entry { - c.runningMu.Lock() - defer c.runningMu.Unlock() - if c.running { - replyChan := make(chan []Entry, 1) - c.snapshot <- replyChan - return <-replyChan - } - return c.entrySnapshot() -} - -// Location gets the time zone location -func (c *Cron) Location() *time.Location { - return c.location -} - -// Entry returns a snapshot of the given entry, or nil if it couldn't be found. -func (c *Cron) Entry(id EntryID) Entry { - for _, entry := range c.Entries() { - if id == entry.ID { - return entry - } - } - return Entry{} -} - -// Remove an entry from being run in the future. -func (c *Cron) Remove(id EntryID) { - c.runningMu.Lock() - defer c.runningMu.Unlock() - if c.running { - c.remove <- id - } else { - c.removeEntry(id) - } -} - -// Start the cron scheduler in its own goroutine, or no-op if already started. -func (c *Cron) Start() { - c.runningMu.Lock() - defer c.runningMu.Unlock() - if c.running { - return - } - c.running = true - go c.run() -} - -// Run the cron scheduler, or no-op if already running. -func (c *Cron) Run() { - c.runningMu.Lock() - if c.running { - c.runningMu.Unlock() - return - } - c.running = true - c.runningMu.Unlock() - c.run() -} - -// run the scheduler.. this is private just due to the need to synchronize -// access to the 'running' state variable. -func (c *Cron) run() { - c.logger.Info("start") - - // Figure out the next activation times for each entry. - now := c.now() - for _, entry := range c.entries { - entry.Next = entry.Schedule.Next(now) - c.logger.Info("schedule", "now", now, "entry", entry.ID, "next", entry.Next) - } - - for { - // Determine the next entry to run. - sort.Sort(byTime(c.entries)) - - var timer *time.Timer - if len(c.entries) == 0 || c.entries[0].Next.IsZero() { - // If there are no entries yet, just sleep - it still handles new entries - // and stop requests. - timer = time.NewTimer(100000 * time.Hour) - } else { - timer = time.NewTimer(c.entries[0].Next.Sub(now)) - } - - for { - select { - case now = <-timer.C: - now = now.In(c.location) - c.logger.Info("wake", "now", now) - - // Run every entry whose next time was less than now - for _, e := range c.entries { - if e.Next.After(now) || e.Next.IsZero() { - break - } - c.startJob(e.WrappedJob) - e.Prev = e.Next - e.Next = e.Schedule.Next(now) - c.logger.Info("run", "now", now, "entry", e.ID, "next", e.Next) - } - - case newEntry := <-c.add: - timer.Stop() - now = c.now() - newEntry.Next = newEntry.Schedule.Next(now) - c.entries = append(c.entries, newEntry) - c.logger.Info("added", "now", now, "entry", newEntry.ID, "next", newEntry.Next) - - case replyChan := <-c.snapshot: - replyChan <- c.entrySnapshot() - continue - - case <-c.stop: - timer.Stop() - c.logger.Info("stop") - return - - case id := <-c.remove: - timer.Stop() - now = c.now() - c.removeEntry(id) - c.logger.Info("removed", "entry", id) - } - - break - } - } -} - -// startJob runs the given job in a new goroutine. -func (c *Cron) startJob(j Job) { - c.jobWaiter.Add(1) - go func() { - defer c.jobWaiter.Done() - j.Run() - }() -} - -// now returns current time in c location -func (c *Cron) now() time.Time { - return time.Now().In(c.location) -} - -// Stop stops the cron scheduler if it is running; otherwise it does nothing. -// A context is returned so the caller can wait for running jobs to complete. -func (c *Cron) Stop() context.Context { - c.runningMu.Lock() - defer c.runningMu.Unlock() - if c.running { - c.stop <- struct{}{} - c.running = false - } - ctx, cancel := context.WithCancel(context.Background()) - go func() { - c.jobWaiter.Wait() - cancel() - }() - return ctx -} - -// entrySnapshot returns a copy of the current cron entry list. -func (c *Cron) entrySnapshot() []Entry { - var entries = make([]Entry, len(c.entries)) - for i, e := range c.entries { - entries[i] = *e - } - return entries -} - -func (c *Cron) removeEntry(id EntryID) { - var entries []*Entry - for _, e := range c.entries { - if e.ID != id { - entries = append(entries, e) - } - } - c.entries = entries -} diff --git a/backend/lib/cron/cron_test.go b/backend/lib/cron/cron_test.go deleted file mode 100644 index 35266df1..00000000 --- a/backend/lib/cron/cron_test.go +++ /dev/null @@ -1,699 +0,0 @@ -package cron - -import ( - "bytes" - "fmt" - "log" - "strings" - "sync" - "sync/atomic" - "testing" - "time" -) - -// Many tests schedule a job for every second, and then wait at most a second -// for it to run. This amount is just slightly larger than 1 second to -// compensate for a few milliseconds of runtime. -const OneSecond = 1*time.Second + 50*time.Millisecond - -type syncWriter struct { - wr bytes.Buffer - m sync.Mutex -} - -func (sw *syncWriter) Write(data []byte) (n int, err error) { - sw.m.Lock() - n, err = sw.wr.Write(data) - sw.m.Unlock() - return -} - -func (sw *syncWriter) String() string { - sw.m.Lock() - defer sw.m.Unlock() - return sw.wr.String() -} - -func newBufLogger(sw *syncWriter) Logger { - return PrintfLogger(log.New(sw, "", log.LstdFlags)) -} - -func TestFuncPanicRecovery(t *testing.T) { - var buf syncWriter - cron := New(WithParser(secondParser), - WithChain(Recover(newBufLogger(&buf)))) - cron.Start() - defer cron.Stop() - _, _ = cron.AddFunc("* * * * * ?", func() { - panic("YOLO") - }) - <-time.After(OneSecond) - if !strings.Contains(buf.String(), "YOLO") { - t.Error("expected a panic to be logged, got none") - } - -} - -type DummyJob struct{} - -func (d DummyJob) Run() { - panic("YOLO") -} - -func TestJobPanicRecovery(t *testing.T) { - var job DummyJob - - var buf syncWriter - cron := New(WithParser(secondParser), - WithChain(Recover(newBufLogger(&buf)))) - cron.Start() - defer cron.Stop() - _, _ = cron.AddJob("* * * * * ?", job) - - select { - case <-time.After(OneSecond): - if !strings.Contains(buf.String(), "YOLO") { - t.Error("expected a panic to be logged, got none") - } - return - } -} - -// Start and stop cron with no entries. -func TestNoEntries(t *testing.T) { - cron := newWithSeconds() - cron.Start() - - select { - case <-time.After(OneSecond): - t.Fatal("expected cron will be stopped immediately") - case <-stop(cron): - } -} - -// Start, stop, then add an entry. Verify entry doesn't run. -func TestStopCausesJobsToNotRun(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - cron := newWithSeconds() - cron.Start() - cron.Stop() - _, _ = cron.AddFunc("* * * * * ?", func() { wg.Done() }) - - select { - case <-time.After(OneSecond): - // No job ran! - case <-wait(wg): - t.Fatal("expected stopped cron does not run any job") - } -} - -// Add a job, start cron, expect it runs. -func TestAddBeforeRunning(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - cron := newWithSeconds() - _, _ = cron.AddFunc("* * * * * ?", func() { wg.Done() }) - cron.Start() - defer cron.Stop() - - // Give cron 2 seconds to run our job (which is always activated). - select { - case <-time.After(OneSecond): - t.Fatal("expected job runs") - case <-wait(wg): - } -} - -// Start cron, add a job, expect it runs. -func TestAddWhileRunning(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - cron := newWithSeconds() - cron.Start() - defer cron.Stop() - _, _ = cron.AddFunc("* * * * * ?", func() { wg.Done() }) - - select { - case <-time.After(OneSecond): - t.Fatal("expected job runs") - case <-wait(wg): - } -} - -// Test for #34. Adding a job after calling start results in multiple job invocations -func TestAddWhileRunningWithDelay(t *testing.T) { - cron := newWithSeconds() - cron.Start() - defer cron.Stop() - time.Sleep(5 * time.Second) - var calls int64 - _, _ = cron.AddFunc("* * * * * *", func() { atomic.AddInt64(&calls, 1) }) - - <-time.After(OneSecond) - if atomic.LoadInt64(&calls) != 1 { - t.Errorf("called %d times, expected 1\n", calls) - } -} - -// Add a job, remove a job, start cron, expect nothing runs. -func TestRemoveBeforeRunning(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - cron := newWithSeconds() - id, _ := cron.AddFunc("* * * * * ?", func() { wg.Done() }) - cron.Remove(id) - cron.Start() - defer cron.Stop() - - select { - case <-time.After(OneSecond): - // Success, shouldn't run - case <-wait(wg): - t.FailNow() - } -} - -// Start cron, add a job, remove it, expect it doesn't run. -func TestRemoveWhileRunning(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - cron := newWithSeconds() - cron.Start() - defer cron.Stop() - id, _ := cron.AddFunc("* * * * * ?", func() { wg.Done() }) - cron.Remove(id) - - select { - case <-time.After(OneSecond): - case <-wait(wg): - t.FailNow() - } -} - -// Test timing with Entries. -func TestSnapshotEntries(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - cron := New() - _, _ = cron.AddFunc("@every 2s", func() { wg.Done() }) - cron.Start() - defer cron.Stop() - - // Cron should fire in 2 seconds. After 1 second, call Entries. - select { - case <-time.After(OneSecond): - cron.Entries() - } - - // Even though Entries was called, the cron should fire at the 2 second mark. - select { - case <-time.After(OneSecond): - t.Error("expected job runs at 2 second mark") - case <-wait(wg): - } -} - -// Test that the entries are correctly sorted. -// Add a bunch of long-in-the-future entries, and an immediate entry, and ensure -// that the immediate entry runs immediately. -// Also: Test that multiple jobs run in the same instant. -func TestMultipleEntries(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(2) - - cron := newWithSeconds() - _, _ = cron.AddFunc("0 0 0 1 1 ?", func() {}) - _, _ = cron.AddFunc("* * * * * ?", func() { wg.Done() }) - id1, _ := cron.AddFunc("* * * * * ?", func() { t.Fatal() }) - id2, _ := cron.AddFunc("* * * * * ?", func() { t.Fatal() }) - _, _ = cron.AddFunc("0 0 0 31 12 ?", func() {}) - _, _ = cron.AddFunc("* * * * * ?", func() { wg.Done() }) - - cron.Remove(id1) - cron.Start() - cron.Remove(id2) - defer cron.Stop() - - select { - case <-time.After(OneSecond): - t.Error("expected job run in proper order") - case <-wait(wg): - } -} - -// Test running the same job twice. -func TestRunningJobTwice(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(2) - - cron := newWithSeconds() - _, _ = cron.AddFunc("0 0 0 1 1 ?", func() {}) - _, _ = cron.AddFunc("0 0 0 31 12 ?", func() {}) - _, _ = cron.AddFunc("* * * * * ?", func() { wg.Done() }) - - cron.Start() - defer cron.Stop() - - select { - case <-time.After(2 * OneSecond): - t.Error("expected job fires 2 times") - case <-wait(wg): - } -} - -func TestRunningMultipleSchedules(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(2) - - cron := newWithSeconds() - _, _ = cron.AddFunc("0 0 0 1 1 ?", func() {}) - _, _ = cron.AddFunc("0 0 0 31 12 ?", func() {}) - _, _ = cron.AddFunc("* * * * * ?", func() { wg.Done() }) - cron.Schedule(Every(time.Minute), FuncJob(func() {})) - cron.Schedule(Every(time.Second), FuncJob(func() { wg.Done() })) - cron.Schedule(Every(time.Hour), FuncJob(func() {})) - - cron.Start() - defer cron.Stop() - - select { - case <-time.After(2 * OneSecond): - t.Error("expected job fires 2 times") - case <-wait(wg): - } -} - -// Test that the cron is run in the local time zone (as opposed to UTC). -func TestLocalTimezone(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(2) - - now := time.Now() - // FIX: Issue #205 - // This calculation doesn't work in seconds 58 or 59. - // Take the easy way out and sleep. - if now.Second() >= 58 { - time.Sleep(2 * time.Second) - now = time.Now() - } - spec := fmt.Sprintf("%d,%d %d %d %d %d ?", - now.Second()+1, now.Second()+2, now.Minute(), now.Hour(), now.Day(), now.Month()) - - cron := newWithSeconds() - _, _ = cron.AddFunc(spec, func() { wg.Done() }) - cron.Start() - defer cron.Stop() - - select { - case <-time.After(OneSecond * 2): - t.Error("expected job fires 2 times") - case <-wait(wg): - } -} - -// Test that the cron is run in the given time zone (as opposed to local). -func TestNonLocalTimezone(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(2) - - loc, err := time.LoadLocation("Atlantic/Cape_Verde") - if err != nil { - fmt.Printf("Failed to load time zone Atlantic/Cape_Verde: %+v", err) - t.Fail() - } - - now := time.Now().In(loc) - // FIX: Issue #205 - // This calculation doesn't work in seconds 58 or 59. - // Take the easy way out and sleep. - if now.Second() >= 58 { - time.Sleep(2 * time.Second) - now = time.Now().In(loc) - } - spec := fmt.Sprintf("%d,%d %d %d %d %d ?", - now.Second()+1, now.Second()+2, now.Minute(), now.Hour(), now.Day(), now.Month()) - - cron := New(WithLocation(loc), WithParser(secondParser)) - _, _ = cron.AddFunc(spec, func() { wg.Done() }) - cron.Start() - defer cron.Stop() - - select { - case <-time.After(OneSecond * 2): - t.Error("expected job fires 2 times") - case <-wait(wg): - } -} - -// Test that calling stop before start silently returns without -// blocking the stop channel. -func TestStopWithoutStart(t *testing.T) { - cron := New() - cron.Stop() -} - -type testJob struct { - wg *sync.WaitGroup - name string -} - -func (t testJob) Run() { - t.wg.Done() -} - -// Test that adding an invalid job spec returns an error -func TestInvalidJobSpec(t *testing.T) { - cron := New() - _, err := cron.AddJob("this will not parse", nil) - if err == nil { - t.Errorf("expected an error with invalid spec, got nil") - } -} - -// Test blocking run method behaves as Start() -func TestBlockingRun(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - cron := newWithSeconds() - _, _ = cron.AddFunc("* * * * * ?", func() { wg.Done() }) - - var unblockChan = make(chan struct{}) - - go func() { - cron.Run() - close(unblockChan) - }() - defer cron.Stop() - - select { - case <-time.After(OneSecond): - t.Error("expected job fires") - case <-unblockChan: - t.Error("expected that Run() blocks") - case <-wait(wg): - } -} - -// Test that double-running is a no-op -func TestStartNoop(t *testing.T) { - var tickChan = make(chan struct{}, 2) - - cron := newWithSeconds() - _, _ = cron.AddFunc("* * * * * ?", func() { - tickChan <- struct{}{} - }) - - cron.Start() - defer cron.Stop() - - // Wait for the first firing to ensure the runner is going - <-tickChan - - cron.Start() - - <-tickChan - - // Fail if this job fires again in a short period, indicating a double-run - select { - case <-time.After(time.Millisecond): - case <-tickChan: - t.Error("expected job fires exactly twice") - } -} - -// Simple test using Runnables. -func TestJob(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - cron := newWithSeconds() - _, _ = cron.AddJob("0 0 0 30 Feb ?", testJob{wg, "job0"}) - _, _ = cron.AddJob("0 0 0 1 1 ?", testJob{wg, "job1"}) - job2, _ := cron.AddJob("* * * * * ?", testJob{wg, "job2"}) - _, _ = cron.AddJob("1 0 0 1 1 ?", testJob{wg, "job3"}) - cron.Schedule(Every(5*time.Second+5*time.Nanosecond), testJob{wg, "job4"}) - job5 := cron.Schedule(Every(5*time.Minute), testJob{wg, "job5"}) - - // Test getting an Entry pre-Start. - if actualName := cron.Entry(job2).Job.(testJob).name; actualName != "job2" { - t.Error("wrong job retrieved:", actualName) - } - if actualName := cron.Entry(job5).Job.(testJob).name; actualName != "job5" { - t.Error("wrong job retrieved:", actualName) - } - - cron.Start() - defer cron.Stop() - - select { - case <-time.After(OneSecond): - t.FailNow() - case <-wait(wg): - } - - // Ensure the entries are in the right order. - expecteds := []string{"job2", "job4", "job5", "job1", "job3", "job0"} - - var actuals = make([]string, 0, len(cron.Entries())) - for _, entry := range cron.Entries() { - actuals = append(actuals, entry.Job.(testJob).name) - } - - for i, expected := range expecteds { - if actuals[i] != expected { - t.Fatalf("Jobs not in the right order. (expected) %s != %s (actual)", expecteds, actuals) - } - } - - // Test getting Entries. - if actualName := cron.Entry(job2).Job.(testJob).name; actualName != "job2" { - t.Error("wrong job retrieved:", actualName) - } - if actualName := cron.Entry(job5).Job.(testJob).name; actualName != "job5" { - t.Error("wrong job retrieved:", actualName) - } -} - -// Issue #206 -// Ensure that the next run of a job after removing an entry is accurate. -func TestScheduleAfterRemoval(t *testing.T) { - var wg1 sync.WaitGroup - var wg2 sync.WaitGroup - wg1.Add(1) - wg2.Add(1) - - // The first time this job is run, set a timer and remove the other job - // 750ms later. Correct behavior would be to still run the job again in - // 250ms, but the bug would cause it to run instead 1s later. - - var calls int - var mu sync.Mutex - - cron := newWithSeconds() - hourJob := cron.Schedule(Every(time.Hour), FuncJob(func() {})) - cron.Schedule(Every(time.Second), FuncJob(func() { - mu.Lock() - defer mu.Unlock() - switch calls { - case 0: - wg1.Done() - calls++ - case 1: - time.Sleep(750 * time.Millisecond) - cron.Remove(hourJob) - calls++ - case 2: - calls++ - wg2.Done() - case 3: - panic("unexpected 3rd call") - } - })) - - cron.Start() - defer cron.Stop() - - // the first run might be any length of time 0 - 1s, since the schedule - // rounds to the second. wait for the first run to true up. - wg1.Wait() - - select { - case <-time.After(2 * OneSecond): - t.Error("expected job fires 2 times") - case <-wait(&wg2): - } -} - -type ZeroSchedule struct{} - -func (*ZeroSchedule) Next(time.Time) time.Time { - return time.Time{} -} - -// Tests that job without time does not run -func TestJobWithZeroTimeDoesNotRun(t *testing.T) { - cron := newWithSeconds() - var calls int64 - _, _ = cron.AddFunc("* * * * * *", func() { atomic.AddInt64(&calls, 1) }) - cron.Schedule(new(ZeroSchedule), FuncJob(func() { t.Error("expected zero task will not run") })) - cron.Start() - defer cron.Stop() - <-time.After(OneSecond) - if atomic.LoadInt64(&calls) != 1 { - t.Errorf("called %d times, expected 1\n", calls) - } -} - -func TestStopAndWait(t *testing.T) { - t.Run("nothing running, returns immediately", func(t *testing.T) { - cron := newWithSeconds() - cron.Start() - ctx := cron.Stop() - select { - case <-ctx.Done(): - case <-time.After(time.Millisecond): - t.Error("context was not done immediately") - } - }) - - t.Run("repeated calls to Stop", func(t *testing.T) { - cron := newWithSeconds() - cron.Start() - _ = cron.Stop() - time.Sleep(time.Millisecond) - ctx := cron.Stop() - select { - case <-ctx.Done(): - case <-time.After(time.Millisecond): - t.Error("context was not done immediately") - } - }) - - t.Run("a couple fast jobs added, still returns immediately", func(t *testing.T) { - cron := newWithSeconds() - _, _ = cron.AddFunc("* * * * * *", func() {}) - cron.Start() - _, _ = cron.AddFunc("* * * * * *", func() {}) - _, _ = cron.AddFunc("* * * * * *", func() {}) - _, _ = cron.AddFunc("* * * * * *", func() {}) - time.Sleep(time.Second) - ctx := cron.Stop() - select { - case <-ctx.Done(): - case <-time.After(time.Millisecond): - t.Error("context was not done immediately") - } - }) - - t.Run("a couple fast jobs and a slow job added, waits for slow job", func(t *testing.T) { - cron := newWithSeconds() - _, _ = cron.AddFunc("* * * * * *", func() {}) - cron.Start() - _, _ = cron.AddFunc("* * * * * *", func() { time.Sleep(2 * time.Second) }) - _, _ = cron.AddFunc("* * * * * *", func() {}) - time.Sleep(time.Second) - - ctx := cron.Stop() - - // Verify that it is not done for at least 750ms - select { - case <-ctx.Done(): - t.Error("context was done too quickly immediately") - case <-time.After(750 * time.Millisecond): - // expected, because the job sleeping for 1 second is still running - } - - // Verify that it IS done in the next 500ms (giving 250ms buffer) - select { - case <-ctx.Done(): - // expected - case <-time.After(1500 * time.Millisecond): - t.Error("context not done after job should have completed") - } - }) - - t.Run("repeated calls to stop, waiting for completion and after", func(t *testing.T) { - cron := newWithSeconds() - _, _ = cron.AddFunc("* * * * * *", func() {}) - _, _ = cron.AddFunc("* * * * * *", func() { time.Sleep(2 * time.Second) }) - cron.Start() - _, _ = cron.AddFunc("* * * * * *", func() {}) - time.Sleep(time.Second) - ctx := cron.Stop() - ctx2 := cron.Stop() - - // Verify that it is not done for at least 1500ms - select { - case <-ctx.Done(): - t.Error("context was done too quickly immediately") - case <-ctx2.Done(): - t.Error("context2 was done too quickly immediately") - case <-time.After(1500 * time.Millisecond): - // expected, because the job sleeping for 2 seconds is still running - } - - // Verify that it IS done in the next 1s (giving 500ms buffer) - select { - case <-ctx.Done(): - // expected - case <-time.After(time.Second): - t.Error("context not done after job should have completed") - } - - // Verify that ctx2 is also done. - select { - case <-ctx2.Done(): - // expected - case <-time.After(time.Millisecond): - t.Error("context2 not done even though context1 is") - } - - // Verify that a new context retrieved from stop is immediately done. - ctx3 := cron.Stop() - select { - case <-ctx3.Done(): - // expected - case <-time.After(time.Millisecond): - t.Error("context not done even when cron Stop is completed") - } - - }) -} - -func TestMultiThreadedStartAndStop(t *testing.T) { - cron := New() - go cron.Run() - time.Sleep(2 * time.Millisecond) - cron.Stop() -} - -func wait(wg *sync.WaitGroup) chan bool { - ch := make(chan bool) - go func() { - wg.Wait() - ch <- true - }() - return ch -} - -func stop(cron *Cron) chan bool { - ch := make(chan bool) - go func() { - cron.Stop() - ch <- true - }() - return ch -} - -// newWithSeconds returns a Cron with the seconds field enabled. -func newWithSeconds() *Cron { - return New(WithParser(secondParser), WithChain()) -} diff --git a/backend/lib/cron/doc.go b/backend/lib/cron/doc.go deleted file mode 100644 index fbee72c1..00000000 --- a/backend/lib/cron/doc.go +++ /dev/null @@ -1,212 +0,0 @@ -/* -Package cron implements a cron spec parser and job runner. - -Usage - -Callers may register Funcs to be invoked on a given schedule. Cron will run -them in their own goroutines. - - c := cron.New() - c.AddFunc("30 * * * *", func() { fmt.Println("Every hour on the half hour") }) - c.AddFunc("30 3-6,20-23 * * *", func() { fmt.Println(".. in the range 3-6am, 8-11pm") }) - c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") }) - c.AddFunc("@hourly", func() { fmt.Println("Every hour, starting an hour from now") }) - c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty, starting an hour thirty from now") }) - c.Start() - .. - // Funcs are invoked in their own goroutine, asynchronously. - ... - // Funcs may also be added to a running Cron - c.AddFunc("@daily", func() { fmt.Println("Every day") }) - .. - // Inspect the cron job entries' next and previous run times. - inspect(c.Entries()) - .. - c.Stop() // Stop the scheduler (does not stop any jobs already running). - -CRON Expression Format - -A cron expression represents a set of times, using 5 space-separated fields. - - Field name | Mandatory? | Allowed values | Allowed special characters - ---------- | ---------- | -------------- | -------------------------- - Minutes | Yes | 0-59 | * / , - - Hours | Yes | 0-23 | * / , - - Day of month | Yes | 1-31 | * / , - ? - Month | Yes | 1-12 or JAN-DEC | * / , - - Day of week | Yes | 0-6 or SUN-SAT | * / , - ? - -Month and Day-of-week field values are case insensitive. "SUN", "Sun", and -"sun" are equally accepted. - -The specific interpretation of the format is based on the Cron Wikipedia page: -https://en.wikipedia.org/wiki/Cron - -Alternative Formats - -Alternative Cron expression formats support other fields like seconds. You can -implement that by creating a custom Parser as follows. - - cron.New( - cron.WithParser( - cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)) - -The most popular alternative Cron expression format is Quartz: -http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html - -Special Characters - -Asterisk ( * ) - -The asterisk indicates that the cron expression will match for all values of the -field; e.g., using an asterisk in the 5th field (month) would indicate every -month. - -Slash ( / ) - -Slashes are used to describe increments of ranges. For example 3-59/15 in the -1st field (minutes) would indicate the 3rd minute of the hour and every 15 -minutes thereafter. The form "*\/..." is equivalent to the form "first-last/...", -that is, an increment over the largest possible range of the field. The form -"N/..." is accepted as meaning "N-MAX/...", that is, starting at N, use the -increment until the end of that specific range. It does not wrap around. - -Comma ( , ) - -Commas are used to separate items of a list. For example, using "MON,WED,FRI" in -the 5th field (day of week) would mean Mondays, Wednesdays and Fridays. - -Hyphen ( - ) - -Hyphens are used to define ranges. For example, 9-17 would indicate every -hour between 9am and 5pm inclusive. - -Question mark ( ? ) - -Question mark may be used instead of '*' for leaving either day-of-month or -day-of-week blank. - -Predefined schedules - -You may use one of several pre-defined schedules in place of a cron expression. - - Entry | Description | Equivalent To - ----- | ----------- | ------------- - @yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 1 1 * - @monthly | Run once a month, midnight, first of month | 0 0 1 * * - @weekly | Run once a week, midnight between Sat/Sun | 0 0 * * 0 - @daily (or @midnight) | Run once a day, midnight | 0 0 * * * - @hourly | Run once an hour, beginning of hour | 0 * * * * - -Intervals - -You may also schedule a job to execute at fixed intervals, starting at the time it's added -or cron is run. This is supported by formatting the cron spec like this: - - @every - -where "duration" is a string accepted by time.ParseDuration -(http://golang.org/pkg/time/#ParseDuration). - -For example, "@every 1h30m10s" would indicate a schedule that activates after -1 hour, 30 minutes, 10 seconds, and then every interval after that. - -Note: The interval does not take the job runtime into account. For example, -if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes, -it will have only 2 minutes of idle time between each run. - -Time zones - -By default, all interpretation and scheduling is done in the machine's local -time zone (time.Local). You can specify a different time zone on construction: - - cron.New( - cron.WithLocation(time.UTC)) - -Individual cron schedules may also override the time zone they are to be -interpreted in by providing an additional space-separated field at the beginning -of the cron spec, of the form "CRON_TZ=Asia/Tokyo". - -For example: - - # Runs at 6am in time.Local - cron.New().AddFunc("0 6 * * ?", ...) - - # Runs at 6am in America/New_York - nyc, _ := time.LoadLocation("America/New_York") - c := cron.New(cron.WithLocation(nyc)) - c.AddFunc("0 6 * * ?", ...) - - # Runs at 6am in Asia/Tokyo - cron.New().AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", ...) - - # Runs at 6am in Asia/Tokyo - c := cron.New(cron.WithLocation(nyc)) - c.SetLocation("America/New_York") - c.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", ...) - -The prefix "TZ=(TIME ZONE)" is also supported for legacy compatibility. - -Be aware that jobs scheduled during daylight-savings leap-ahead transitions will -not be run! - -Job Wrappers / Chain - -A Cron runner may be configured with a chain of job wrappers to add -cross-cutting functionality to all submitted jobs. For example, they may be used -to achieve the following effects: - - - Recover any panics from jobs (activated by default) - - Delay a job's execution if the previous run hasn't completed yet - - Skip a job's execution if the previous run hasn't completed yet - - Log each job's invocations - -Install wrappers for all jobs added to a cron using the `cron.WithChain` option: - - cron.New(cron.WithChain( - cron.SkipIfStillRunning(logger), - )) - -Install wrappers for individual jobs by explicitly wrapping them: - - job = cron.NewChain( - cron.SkipIfStillRunning(logger), - ).Then(job) - -Thread safety - -Since the Cron service runs concurrently with the calling code, some amount of -care must be taken to ensure proper synchronization. - -All cron methods are designed to be correctly synchronized as long as the caller -ensures that invocations have a clear happens-before ordering between them. - -Logging - -Cron defines a Logger interface that is a subset of the one defined in -github.com/go-logr/logr. It has two logging levels (Info and Error), and -parameters are key/value pairs. This makes it possible for cron logging to plug -into structured logging systems. An adapter, [Verbose]PrintfLogger, is provided -to wrap the standard library *log.Logger. - -For additional insight into Cron operations, verbose logging may be activated -which will record job runs, scheduling decisions, and added or removed jobs. -Activate it with a one-off logger as follows: - - cron.New( - cron.WithLogger( - cron.VerbosePrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags)))) - - -Implementation - -Cron entries are stored in an array, sorted by their next activation time. Cron -sleeps until the next job is due to be run. - -Upon waking: - - it runs each entry that is active on that second - - it calculates the next run times for the jobs that were run - - it re-sorts the array of entries by next activation time. - - it goes to sleep until the soonest job. -*/ -package cron diff --git a/backend/lib/cron/logger.go b/backend/lib/cron/logger.go deleted file mode 100644 index 46314da8..00000000 --- a/backend/lib/cron/logger.go +++ /dev/null @@ -1,86 +0,0 @@ -package cron - -import ( - "io/ioutil" - "log" - "os" - "strings" - "time" -) - -// DefaultLogger is used by Cron if none is specified. -var DefaultLogger = PrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags)) - -// DiscardLogger can be used by callers to discard all log messages. -var DiscardLogger = PrintfLogger(log.New(ioutil.Discard, "", 0)) - -// Logger is the interface used in this package for logging, so that any backend -// can be plugged in. It is a subset of the github.com/go-logr/logr interface. -type Logger interface { - // Info logs routine messages about cron's operation. - Info(msg string, keysAndValues ...interface{}) - // Error logs an error condition. - Error(err error, msg string, keysAndValues ...interface{}) -} - -// PrintfLogger wraps a Printf-based logger (such as the standard library "log") -// into an implementation of the Logger interface which logs errors only. -func PrintfLogger(l interface{ Printf(string, ...interface{}) }) Logger { - return printfLogger{l, false} -} - -// VerbosePrintfLogger wraps a Printf-based logger (such as the standard library -// "log") into an implementation of the Logger interface which logs everything. -func VerbosePrintfLogger(l interface{ Printf(string, ...interface{}) }) Logger { - return printfLogger{l, true} -} - -type printfLogger struct { - logger interface{ Printf(string, ...interface{}) } - logInfo bool -} - -func (pl printfLogger) Info(msg string, keysAndValues ...interface{}) { - if pl.logInfo { - keysAndValues = formatTimes(keysAndValues) - pl.logger.Printf( - formatString(len(keysAndValues)), - append([]interface{}{msg}, keysAndValues...)...) - } -} - -func (pl printfLogger) Error(err error, msg string, keysAndValues ...interface{}) { - keysAndValues = formatTimes(keysAndValues) - pl.logger.Printf( - formatString(len(keysAndValues)+2), - append([]interface{}{msg, "error", err}, keysAndValues...)...) -} - -// formatString returns a logfmt-like format string for the number of -// key/values. -func formatString(numKeysAndValues int) string { - var sb strings.Builder - sb.WriteString("%s") - if numKeysAndValues > 0 { - sb.WriteString(", ") - } - for i := 0; i < numKeysAndValues/2; i++ { - if i > 0 { - sb.WriteString(", ") - } - sb.WriteString("%v=%v") - } - return sb.String() -} - -// formatTimes formats any time.Time values as RFC3339. -func formatTimes(keysAndValues []interface{}) []interface{} { - var formattedArgs []interface{} - for _, arg := range keysAndValues { - if t, ok := arg.(time.Time); ok { - arg = t.Format(time.RFC3339) - } - formattedArgs = append(formattedArgs, arg) - } - return formattedArgs -} diff --git a/backend/lib/cron/option.go b/backend/lib/cron/option.go deleted file mode 100644 index 07638201..00000000 --- a/backend/lib/cron/option.go +++ /dev/null @@ -1,45 +0,0 @@ -package cron - -import ( - "time" -) - -// Option represents a modification to the default behavior of a Cron. -type Option func(*Cron) - -// WithLocation overrides the timezone of the cron instance. -func WithLocation(loc *time.Location) Option { - return func(c *Cron) { - c.location = loc - } -} - -// WithSeconds overrides the parser used for interpreting job schedules to -// include a seconds field as the first one. -func WithSeconds() Option { - return WithParser(NewParser( - Second | Minute | Hour | Dom | Month | Dow | Descriptor, - )) -} - -// WithParser overrides the parser used for interpreting job schedules. -func WithParser(p Parser) Option { - return func(c *Cron) { - c.parser = p - } -} - -// WithChain specifies Job wrappers to apply to all jobs added to this cron. -// Refer to the Chain* functions in this package for provided wrappers. -func WithChain(wrappers ...JobWrapper) Option { - return func(c *Cron) { - c.chain = NewChain(wrappers...) - } -} - -// WithLogger uses the provided logger. -func WithLogger(logger Logger) Option { - return func(c *Cron) { - c.logger = logger - } -} diff --git a/backend/lib/cron/option_test.go b/backend/lib/cron/option_test.go deleted file mode 100644 index 57dbaa4b..00000000 --- a/backend/lib/cron/option_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package cron - -import ( - "log" - "strings" - "testing" - "time" -) - -func TestWithLocation(t *testing.T) { - c := New(WithLocation(time.UTC)) - if c.location != time.UTC { - t.Errorf("expected UTC, got %v", c.location) - } -} - -func TestWithParser(t *testing.T) { - var parser = NewParser(Dow) - c := New(WithParser(parser)) - if c.parser != parser { - t.Error("expected provided parser") - } -} - -func TestWithVerboseLogger(t *testing.T) { - var buf syncWriter - var logger = log.New(&buf, "", log.LstdFlags) - c := New(WithLogger(VerbosePrintfLogger(logger))) - if c.logger.(printfLogger).logger != logger { - t.Error("expected provided logger") - } - - _, _ = c.AddFunc("@every 1s", func() {}) - c.Start() - time.Sleep(OneSecond) - c.Stop() - out := buf.String() - if !strings.Contains(out, "schedule,") || - !strings.Contains(out, "run,") { - t.Error("expected to see some actions, got:", out) - } -} diff --git a/backend/lib/cron/parser.go b/backend/lib/cron/parser.go deleted file mode 100644 index 3cf8879f..00000000 --- a/backend/lib/cron/parser.go +++ /dev/null @@ -1,434 +0,0 @@ -package cron - -import ( - "fmt" - "math" - "strconv" - "strings" - "time" -) - -// Configuration options for creating a parser. Most options specify which -// fields should be included, while others enable features. If a field is not -// included the parser will assume a default value. These options do not change -// the order fields are parse in. -type ParseOption int - -const ( - Second ParseOption = 1 << iota // Seconds field, default 0 - SecondOptional // Optional seconds field, default 0 - Minute // Minutes field, default 0 - Hour // Hours field, default 0 - Dom // Day of month field, default * - Month // Month field, default * - Dow // Day of week field, default * - DowOptional // Optional day of week field, default * - Descriptor // Allow descriptors such as @monthly, @weekly, etc. -) - -var places = []ParseOption{ - Second, - Minute, - Hour, - Dom, - Month, - Dow, -} - -var defaults = []string{ - "0", - "0", - "0", - "*", - "*", - "*", -} - -// A custom Parser that can be configured. -type Parser struct { - options ParseOption -} - -// NewParser creates a Parser with custom options. -// -// It panics if more than one Optional is given, since it would be impossible to -// correctly infer which optional is provided or missing in general. -// -// Examples -// -// // Standard parser without descriptors -// specParser := NewParser(Minute | Hour | Dom | Month | Dow) -// sched, err := specParser.Parse("0 0 15 */3 *") -// -// // Same as above, just excludes time fields -// subsParser := NewParser(Dom | Month | Dow) -// sched, err := specParser.Parse("15 */3 *") -// -// // Same as above, just makes Dow optional -// subsParser := NewParser(Dom | Month | DowOptional) -// sched, err := specParser.Parse("15 */3") -// -func NewParser(options ParseOption) Parser { - optionals := 0 - if options&DowOptional > 0 { - optionals++ - } - if options&SecondOptional > 0 { - optionals++ - } - if optionals > 1 { - panic("multiple optionals may not be configured") - } - return Parser{options} -} - -// Parse returns a new crontab schedule representing the given spec. -// It returns a descriptive error if the spec is not valid. -// It accepts crontab specs and features configured by NewParser. -func (p Parser) Parse(spec string) (Schedule, error) { - if len(spec) == 0 { - return nil, fmt.Errorf("empty spec string") - } - - // Extract timezone if present - var loc = time.Local - if strings.HasPrefix(spec, "TZ=") || strings.HasPrefix(spec, "CRON_TZ=") { - var err error - i := strings.Index(spec, " ") - eq := strings.Index(spec, "=") - if loc, err = time.LoadLocation(spec[eq+1 : i]); err != nil { - return nil, fmt.Errorf("provided bad location %s: %v", spec[eq+1:i], err) - } - spec = strings.TrimSpace(spec[i:]) - } - - // Handle named schedules (descriptors), if configured - if strings.HasPrefix(spec, "@") { - if p.options&Descriptor == 0 { - return nil, fmt.Errorf("parser does not accept descriptors: %v", spec) - } - return parseDescriptor(spec, loc) - } - - // Split on whitespace. - fields := strings.Fields(spec) - - // Validate & fill in any omitted or optional fields - var err error - fields, err = normalizeFields(fields, p.options) - if err != nil { - return nil, err - } - - field := func(field string, r bounds) uint64 { - if err != nil { - return 0 - } - var bits uint64 - bits, err = getField(field, r) - return bits - } - - var ( - second = field(fields[0], seconds) - minute = field(fields[1], minutes) - hour = field(fields[2], hours) - dayofmonth = field(fields[3], dom) - month = field(fields[4], months) - dayofweek = field(fields[5], dow) - ) - if err != nil { - return nil, err - } - - return &SpecSchedule{ - Second: second, - Minute: minute, - Hour: hour, - Dom: dayofmonth, - Month: month, - Dow: dayofweek, - Location: loc, - }, nil -} - -// normalizeFields takes a subset set of the time fields and returns the full set -// with defaults (zeroes) populated for unset fields. -// -// As part of performing this function, it also validates that the provided -// fields are compatible with the configured options. -func normalizeFields(fields []string, options ParseOption) ([]string, error) { - // Validate optionals & add their field to options - optionals := 0 - if options&SecondOptional > 0 { - options |= Second - optionals++ - } - if options&DowOptional > 0 { - options |= Dow - optionals++ - } - if optionals > 1 { - return nil, fmt.Errorf("multiple optionals may not be configured") - } - - // Figure out how many fields we need - max := 0 - for _, place := range places { - if options&place > 0 { - max++ - } - } - min := max - optionals - - // Validate number of fields - if count := len(fields); count < min || count > max { - if min == max { - return nil, fmt.Errorf("expected exactly %d fields, found %d: %s", min, count, fields) - } - return nil, fmt.Errorf("expected %d to %d fields, found %d: %s", min, max, count, fields) - } - - // Populate the optional field if not provided - if min < max && len(fields) == min { - switch { - case options&DowOptional > 0: - fields = append(fields, defaults[5]) // TODO: improve access to default - case options&SecondOptional > 0: - fields = append([]string{defaults[0]}, fields...) - default: - return nil, fmt.Errorf("unknown optional field") - } - } - - // Populate all fields not part of options with their defaults - n := 0 - expandedFields := make([]string, len(places)) - copy(expandedFields, defaults) - for i, place := range places { - if options&place > 0 { - expandedFields[i] = fields[n] - n++ - } - } - return expandedFields, nil -} - -var standardParser = NewParser( - Minute | Hour | Dom | Month | Dow | Descriptor, -) - -// ParseStandard returns a new crontab schedule representing the given -// standardSpec (https://en.wikipedia.org/wiki/Cron). It requires 5 entries -// representing: minute, hour, day of month, month and day of week, in that -// order. It returns a descriptive error if the spec is not valid. -// -// It accepts -// - Standard crontab specs, e.g. "* * * * ?" -// - Descriptors, e.g. "@midnight", "@every 1h30m" -func ParseStandard(standardSpec string) (Schedule, error) { - return standardParser.Parse(standardSpec) -} - -// getField returns an Int with the bits set representing all of the times that -// the field represents or error parsing field value. A "field" is a comma-separated -// list of "ranges". -func getField(field string, r bounds) (uint64, error) { - var bits uint64 - ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' }) - for _, expr := range ranges { - bit, err := getRange(expr, r) - if err != nil { - return bits, err - } - bits |= bit - } - return bits, nil -} - -// getRange returns the bits indicated by the given expression: -// number | number "-" number [ "/" number ] -// or error parsing range. -func getRange(expr string, r bounds) (uint64, error) { - var ( - start, end, step uint - rangeAndStep = strings.Split(expr, "/") - lowAndHigh = strings.Split(rangeAndStep[0], "-") - singleDigit = len(lowAndHigh) == 1 - err error - ) - - var extra uint64 - if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" { - start = r.min - end = r.max - extra = starBit - } else { - start, err = parseIntOrName(lowAndHigh[0], r.names) - if err != nil { - return 0, err - } - switch len(lowAndHigh) { - case 1: - end = start - case 2: - end, err = parseIntOrName(lowAndHigh[1], r.names) - if err != nil { - return 0, err - } - default: - return 0, fmt.Errorf("too many hyphens: %s", expr) - } - } - - switch len(rangeAndStep) { - case 1: - step = 1 - case 2: - step, err = mustParseInt(rangeAndStep[1]) - if err != nil { - return 0, err - } - - // Special handling: "N/step" means "N-max/step". - if singleDigit { - end = r.max - } - if step > 1 { - extra = 0 - } - default: - return 0, fmt.Errorf("too many slashes: %s", expr) - } - - if start < r.min { - return 0, fmt.Errorf("beginning of range (%d) below minimum (%d): %s", start, r.min, expr) - } - if end > r.max { - return 0, fmt.Errorf("end of range (%d) above maximum (%d): %s", end, r.max, expr) - } - if start > end { - return 0, fmt.Errorf("beginning of range (%d) beyond end of range (%d): %s", start, end, expr) - } - if step == 0 { - return 0, fmt.Errorf("step of range should be a positive number: %s", expr) - } - - return getBits(start, end, step) | extra, nil -} - -// parseIntOrName returns the (possibly-named) integer contained in expr. -func parseIntOrName(expr string, names map[string]uint) (uint, error) { - if names != nil { - if namedInt, ok := names[strings.ToLower(expr)]; ok { - return namedInt, nil - } - } - return mustParseInt(expr) -} - -// mustParseInt parses the given expression as an int or returns an error. -func mustParseInt(expr string) (uint, error) { - num, err := strconv.Atoi(expr) - if err != nil { - return 0, fmt.Errorf("failed to parse int from %s: %s", expr, err) - } - if num < 0 { - return 0, fmt.Errorf("negative number (%d) not allowed: %s", num, expr) - } - - return uint(num), nil -} - -// getBits sets all bits in the range [min, max], modulo the given step size. -func getBits(min, max, step uint) uint64 { - var bits uint64 - - // If step is 1, use shifts. - if step == 1 { - return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min) - } - - // Else, use a simple loop. - for i := min; i <= max; i += step { - bits |= 1 << i - } - return bits -} - -// all returns all bits within the given bounds. (plus the star bit) -func all(r bounds) uint64 { - return getBits(r.min, r.max, 1) | starBit -} - -// parseDescriptor returns a predefined schedule for the expression, or error if none matches. -func parseDescriptor(descriptor string, loc *time.Location) (Schedule, error) { - switch descriptor { - case "@yearly", "@annually": - return &SpecSchedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: 1 << hours.min, - Dom: 1 << dom.min, - Month: 1 << months.min, - Dow: all(dow), - Location: loc, - }, nil - - case "@monthly": - return &SpecSchedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: 1 << hours.min, - Dom: 1 << dom.min, - Month: all(months), - Dow: all(dow), - Location: loc, - }, nil - - case "@weekly": - return &SpecSchedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: 1 << hours.min, - Dom: all(dom), - Month: all(months), - Dow: 1 << dow.min, - Location: loc, - }, nil - - case "@daily", "@midnight": - return &SpecSchedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: 1 << hours.min, - Dom: all(dom), - Month: all(months), - Dow: all(dow), - Location: loc, - }, nil - - case "@hourly": - return &SpecSchedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: all(hours), - Dom: all(dom), - Month: all(months), - Dow: all(dow), - Location: loc, - }, nil - - } - - const every = "@every " - if strings.HasPrefix(descriptor, every) { - duration, err := time.ParseDuration(descriptor[len(every):]) - if err != nil { - return nil, fmt.Errorf("failed to parse duration %s: %s", descriptor, err) - } - return Every(duration), nil - } - - return nil, fmt.Errorf("unrecognized descriptor: %s", descriptor) -} diff --git a/backend/lib/cron/parser_test.go b/backend/lib/cron/parser_test.go deleted file mode 100644 index f95a54bb..00000000 --- a/backend/lib/cron/parser_test.go +++ /dev/null @@ -1,384 +0,0 @@ -package cron - -import ( - "reflect" - "strings" - "testing" - "time" -) - -var secondParser = NewParser(Second | Minute | Hour | Dom | Month | DowOptional | Descriptor) - -func TestRange(t *testing.T) { - zero := uint64(0) - ranges := []struct { - expr string - min, max uint - expected uint64 - err string - }{ - {"5", 0, 7, 1 << 5, ""}, - {"0", 0, 7, 1 << 0, ""}, - {"7", 0, 7, 1 << 7, ""}, - - {"5-5", 0, 7, 1 << 5, ""}, - {"5-6", 0, 7, 1<<5 | 1<<6, ""}, - {"5-7", 0, 7, 1<<5 | 1<<6 | 1<<7, ""}, - - {"5-6/2", 0, 7, 1 << 5, ""}, - {"5-7/2", 0, 7, 1<<5 | 1<<7, ""}, - {"5-7/1", 0, 7, 1<<5 | 1<<6 | 1<<7, ""}, - - {"*", 1, 3, 1<<1 | 1<<2 | 1<<3 | starBit, ""}, - {"*/2", 1, 3, 1<<1 | 1<<3, ""}, - - {"5--5", 0, 0, zero, "too many hyphens"}, - {"jan-x", 0, 0, zero, "failed to parse int from"}, - {"2-x", 1, 5, zero, "failed to parse int from"}, - {"*/-12", 0, 0, zero, "negative number"}, - {"*//2", 0, 0, zero, "too many slashes"}, - {"1", 3, 5, zero, "below minimum"}, - {"6", 3, 5, zero, "above maximum"}, - {"5-3", 3, 5, zero, "beyond end of range"}, - {"*/0", 0, 0, zero, "should be a positive number"}, - } - - for _, c := range ranges { - actual, err := getRange(c.expr, bounds{c.min, c.max, nil}) - if len(c.err) != 0 && (err == nil || !strings.Contains(err.Error(), c.err)) { - t.Errorf("%s => expected %v, got %v", c.expr, c.err, err) - } - if len(c.err) == 0 && err != nil { - t.Errorf("%s => unexpected error %v", c.expr, err) - } - if actual != c.expected { - t.Errorf("%s => expected %d, got %d", c.expr, c.expected, actual) - } - } -} - -func TestField(t *testing.T) { - fields := []struct { - expr string - min, max uint - expected uint64 - }{ - {"5", 1, 7, 1 << 5}, - {"5,6", 1, 7, 1<<5 | 1<<6}, - {"5,6,7", 1, 7, 1<<5 | 1<<6 | 1<<7}, - {"1,5-7/2,3", 1, 7, 1<<1 | 1<<5 | 1<<7 | 1<<3}, - } - - for _, c := range fields { - actual, _ := getField(c.expr, bounds{c.min, c.max, nil}) - if actual != c.expected { - t.Errorf("%s => expected %d, got %d", c.expr, c.expected, actual) - } - } -} - -func TestAll(t *testing.T) { - allBits := []struct { - r bounds - expected uint64 - }{ - {minutes, 0xfffffffffffffff}, // 0-59: 60 ones - {hours, 0xffffff}, // 0-23: 24 ones - {dom, 0xfffffffe}, // 1-31: 31 ones, 1 zero - {months, 0x1ffe}, // 1-12: 12 ones, 1 zero - {dow, 0x7f}, // 0-6: 7 ones - } - - for _, c := range allBits { - actual := all(c.r) // all() adds the starBit, so compensate for that.. - if c.expected|starBit != actual { - t.Errorf("%d-%d/%d => expected %b, got %b", - c.r.min, c.r.max, 1, c.expected|starBit, actual) - } - } -} - -func TestBits(t *testing.T) { - bits := []struct { - min, max, step uint - expected uint64 - }{ - {0, 0, 1, 0x1}, - {1, 1, 1, 0x2}, - {1, 5, 2, 0x2a}, // 101010 - {1, 4, 2, 0xa}, // 1010 - } - - for _, c := range bits { - actual := getBits(c.min, c.max, c.step) - if c.expected != actual { - t.Errorf("%d-%d/%d => expected %b, got %b", - c.min, c.max, c.step, c.expected, actual) - } - } -} - -func TestParseScheduleErrors(t *testing.T) { - var tests = []struct{ expr, err string }{ - {"* 5 j * * *", "failed to parse int from"}, - {"@every Xm", "failed to parse duration"}, - {"@unrecognized", "unrecognized descriptor"}, - {"* * * *", "expected 5 to 6 fields"}, - {"", "empty spec string"}, - } - for _, c := range tests { - actual, err := secondParser.Parse(c.expr) - if err == nil || !strings.Contains(err.Error(), c.err) { - t.Errorf("%s => expected %v, got %v", c.expr, c.err, err) - } - if actual != nil { - t.Errorf("expected nil schedule on error, got %v", actual) - } - } -} - -func TestParseSchedule(t *testing.T) { - tokyo, _ := time.LoadLocation("Asia/Tokyo") - entries := []struct { - parser Parser - expr string - expected Schedule - }{ - {secondParser, "0 5 * * * *", every5min(time.Local)}, - {standardParser, "5 * * * *", every5min(time.Local)}, - {secondParser, "CRON_TZ=UTC 0 5 * * * *", every5min(time.UTC)}, - {standardParser, "CRON_TZ=UTC 5 * * * *", every5min(time.UTC)}, - {secondParser, "CRON_TZ=Asia/Tokyo 0 5 * * * *", every5min(tokyo)}, - {secondParser, "@every 5m", ConstantDelaySchedule{5 * time.Minute}}, - {secondParser, "@midnight", midnight(time.Local)}, - {secondParser, "TZ=UTC @midnight", midnight(time.UTC)}, - {secondParser, "TZ=Asia/Tokyo @midnight", midnight(tokyo)}, - {secondParser, "@yearly", annual(time.Local)}, - {secondParser, "@annually", annual(time.Local)}, - { - parser: secondParser, - expr: "* 5 * * * *", - expected: &SpecSchedule{ - Second: all(seconds), - Minute: 1 << 5, - Hour: all(hours), - Dom: all(dom), - Month: all(months), - Dow: all(dow), - Location: time.Local, - }, - }, - } - - for _, c := range entries { - actual, err := c.parser.Parse(c.expr) - if err != nil { - t.Errorf("%s => unexpected error %v", c.expr, err) - } - if !reflect.DeepEqual(actual, c.expected) { - t.Errorf("%s => expected %b, got %b", c.expr, c.expected, actual) - } - } -} - -func TestOptionalSecondSchedule(t *testing.T) { - parser := NewParser(SecondOptional | Minute | Hour | Dom | Month | Dow | Descriptor) - entries := []struct { - expr string - expected Schedule - }{ - {"0 5 * * * *", every5min(time.Local)}, - {"5 5 * * * *", every5min5s(time.Local)}, - {"5 * * * *", every5min(time.Local)}, - } - - for _, c := range entries { - actual, err := parser.Parse(c.expr) - if err != nil { - t.Errorf("%s => unexpected error %v", c.expr, err) - } - if !reflect.DeepEqual(actual, c.expected) { - t.Errorf("%s => expected %b, got %b", c.expr, c.expected, actual) - } - } -} - -func TestNormalizeFields(t *testing.T) { - tests := []struct { - name string - input []string - options ParseOption - expected []string - }{ - { - "AllFields_NoOptional", - []string{"0", "5", "*", "*", "*", "*"}, - Second | Minute | Hour | Dom | Month | Dow | Descriptor, - []string{"0", "5", "*", "*", "*", "*"}, - }, - { - "AllFields_SecondOptional_Provided", - []string{"0", "5", "*", "*", "*", "*"}, - SecondOptional | Minute | Hour | Dom | Month | Dow | Descriptor, - []string{"0", "5", "*", "*", "*", "*"}, - }, - { - "AllFields_SecondOptional_NotProvided", - []string{"5", "*", "*", "*", "*"}, - SecondOptional | Minute | Hour | Dom | Month | Dow | Descriptor, - []string{"0", "5", "*", "*", "*", "*"}, - }, - { - "SubsetFields_NoOptional", - []string{"5", "15", "*"}, - Hour | Dom | Month, - []string{"0", "0", "5", "15", "*", "*"}, - }, - { - "SubsetFields_DowOptional_Provided", - []string{"5", "15", "*", "4"}, - Hour | Dom | Month | DowOptional, - []string{"0", "0", "5", "15", "*", "4"}, - }, - { - "SubsetFields_DowOptional_NotProvided", - []string{"5", "15", "*"}, - Hour | Dom | Month | DowOptional, - []string{"0", "0", "5", "15", "*", "*"}, - }, - { - "SubsetFields_SecondOptional_NotProvided", - []string{"5", "15", "*"}, - SecondOptional | Hour | Dom | Month, - []string{"0", "0", "5", "15", "*", "*"}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual, err := normalizeFields(test.input, test.options) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if !reflect.DeepEqual(actual, test.expected) { - t.Errorf("expected %v, got %v", test.expected, actual) - } - }) - } -} - -func TestNormalizeFields_Errors(t *testing.T) { - tests := []struct { - name string - input []string - options ParseOption - err string - }{ - { - "TwoOptionals", - []string{"0", "5", "*", "*", "*", "*"}, - SecondOptional | Minute | Hour | Dom | Month | DowOptional, - "", - }, - { - "TooManyFields", - []string{"0", "5", "*", "*"}, - SecondOptional | Minute | Hour, - "", - }, - { - "NoFields", - []string{}, - SecondOptional | Minute | Hour, - "", - }, - { - "TooFewFields", - []string{"*"}, - SecondOptional | Minute | Hour, - "", - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual, err := normalizeFields(test.input, test.options) - if err == nil { - t.Errorf("expected an error, got none. results: %v", actual) - return - } - if !strings.Contains(err.Error(), test.err) { - t.Errorf("expected error %q, got %q", test.err, err.Error()) - } - }) - } -} - -func TestStandardSpecSchedule(t *testing.T) { - entries := []struct { - expr string - expected Schedule - err string - }{ - { - expr: "5 * * * *", - expected: &SpecSchedule{1 << seconds.min, 1 << 5, all(hours), all(dom), all(months), all(dow), time.Local}, - }, - { - expr: "@every 5m", - expected: ConstantDelaySchedule{time.Duration(5) * time.Minute}, - }, - { - expr: "5 j * * *", - err: "failed to parse int from", - }, - { - expr: "* * * *", - err: "expected exactly 5 fields", - }, - } - - for _, c := range entries { - actual, err := ParseStandard(c.expr) - if len(c.err) != 0 && (err == nil || !strings.Contains(err.Error(), c.err)) { - t.Errorf("%s => expected %v, got %v", c.expr, c.err, err) - } - if len(c.err) == 0 && err != nil { - t.Errorf("%s => unexpected error %v", c.expr, err) - } - if !reflect.DeepEqual(actual, c.expected) { - t.Errorf("%s => expected %b, got %b", c.expr, c.expected, actual) - } - } -} - -func TestNoDescriptorParser(t *testing.T) { - parser := NewParser(Minute | Hour) - _, err := parser.Parse("@every 1m") - if err == nil { - t.Error("expected an error, got none") - } -} - -func every5min(loc *time.Location) *SpecSchedule { - return &SpecSchedule{1 << 0, 1 << 5, all(hours), all(dom), all(months), all(dow), loc} -} - -func every5min5s(loc *time.Location) *SpecSchedule { - return &SpecSchedule{1 << 5, 1 << 5, all(hours), all(dom), all(months), all(dow), loc} -} - -func midnight(loc *time.Location) *SpecSchedule { - return &SpecSchedule{1, 1, 1, all(dom), all(months), all(dow), loc} -} - -func annual(loc *time.Location) *SpecSchedule { - return &SpecSchedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: 1 << hours.min, - Dom: 1 << dom.min, - Month: 1 << months.min, - Dow: all(dow), - Location: loc, - } -} diff --git a/backend/lib/cron/spec.go b/backend/lib/cron/spec.go deleted file mode 100644 index 9821a6a2..00000000 --- a/backend/lib/cron/spec.go +++ /dev/null @@ -1,188 +0,0 @@ -package cron - -import "time" - -// SpecSchedule specifies a duty cycle (to the second granularity), based on a -// traditional crontab specification. It is computed initially and stored as bit sets. -type SpecSchedule struct { - Second, Minute, Hour, Dom, Month, Dow uint64 - - // Override location for this schedule. - Location *time.Location -} - -// bounds provides a range of acceptable values (plus a map of name to value). -type bounds struct { - min, max uint - names map[string]uint -} - -// The bounds for each field. -var ( - seconds = bounds{0, 59, nil} - minutes = bounds{0, 59, nil} - hours = bounds{0, 23, nil} - dom = bounds{1, 31, nil} - months = bounds{1, 12, map[string]uint{ - "jan": 1, - "feb": 2, - "mar": 3, - "apr": 4, - "may": 5, - "jun": 6, - "jul": 7, - "aug": 8, - "sep": 9, - "oct": 10, - "nov": 11, - "dec": 12, - }} - dow = bounds{0, 6, map[string]uint{ - "sun": 0, - "mon": 1, - "tue": 2, - "wed": 3, - "thu": 4, - "fri": 5, - "sat": 6, - }} -) - -const ( - // Set the top bit if a star was included in the expression. - starBit = 1 << 63 -) - -// Next returns the next time this schedule is activated, greater than the given -// time. If no time can be found to satisfy the schedule, return the zero time. -func (s *SpecSchedule) Next(t time.Time) time.Time { - // General approach - // - // For Month, Day, Hour, Minute, Second: - // Check if the time value matches. If yes, continue to the next field. - // If the field doesn't match the schedule, then increment the field until it matches. - // While incrementing the field, a wrap-around brings it back to the beginning - // of the field list (since it is necessary to re-verify previous field - // values) - - // Convert the given time into the schedule's timezone, if one is specified. - // Save the original timezone so we can convert back after we find a time. - // Note that schedules without a time zone specified (time.Local) are treated - // as local to the time provided. - origLocation := t.Location() - loc := s.Location - if loc == time.Local { - loc = t.Location() - } - if s.Location != time.Local { - t = t.In(s.Location) - } - - // Start at the earliest possible time (the upcoming second). - t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond) - - // This flag indicates whether a field has been incremented. - added := false - - // If no time is found within five years, return zero. - yearLimit := t.Year() + 5 - -WRAP: - if t.Year() > yearLimit { - return time.Time{} - } - - // Find the first applicable month. - // If it's this month, then do nothing. - for 1< 12 { - t = t.Add(time.Duration(24-t.Hour()) * time.Hour) - } else { - t = t.Add(time.Duration(-t.Hour()) * time.Hour) - } - } - - if t.Day() == 1 { - goto WRAP - } - } - - for 1< 0 - dowMatch = 1< 0 - ) - if s.Dom&starBit > 0 || s.Dow&starBit > 0 { - return domMatch && dowMatch - } - return domMatch || dowMatch -} diff --git a/backend/lib/cron/spec_test.go b/backend/lib/cron/spec_test.go deleted file mode 100644 index 1b8a503e..00000000 --- a/backend/lib/cron/spec_test.go +++ /dev/null @@ -1,300 +0,0 @@ -package cron - -import ( - "strings" - "testing" - "time" -) - -func TestActivation(t *testing.T) { - tests := []struct { - time, spec string - expected bool - }{ - // Every fifteen minutes. - {"Mon Jul 9 15:00 2012", "0/15 * * * *", true}, - {"Mon Jul 9 15:45 2012", "0/15 * * * *", true}, - {"Mon Jul 9 15:40 2012", "0/15 * * * *", false}, - - // Every fifteen minutes, starting at 5 minutes. - {"Mon Jul 9 15:05 2012", "5/15 * * * *", true}, - {"Mon Jul 9 15:20 2012", "5/15 * * * *", true}, - {"Mon Jul 9 15:50 2012", "5/15 * * * *", true}, - - // Named months - {"Sun Jul 15 15:00 2012", "0/15 * * Jul *", true}, - {"Sun Jul 15 15:00 2012", "0/15 * * Jun *", false}, - - // Everything set. - {"Sun Jul 15 08:30 2012", "30 08 ? Jul Sun", true}, - {"Sun Jul 15 08:30 2012", "30 08 15 Jul ?", true}, - {"Mon Jul 16 08:30 2012", "30 08 ? Jul Sun", false}, - {"Mon Jul 16 08:30 2012", "30 08 15 Jul ?", false}, - - // Predefined schedules - {"Mon Jul 9 15:00 2012", "@hourly", true}, - {"Mon Jul 9 15:04 2012", "@hourly", false}, - {"Mon Jul 9 15:00 2012", "@daily", false}, - {"Mon Jul 9 00:00 2012", "@daily", true}, - {"Mon Jul 9 00:00 2012", "@weekly", false}, - {"Sun Jul 8 00:00 2012", "@weekly", true}, - {"Sun Jul 8 01:00 2012", "@weekly", false}, - {"Sun Jul 8 00:00 2012", "@monthly", false}, - {"Sun Jul 1 00:00 2012", "@monthly", true}, - - // Test interaction of DOW and DOM. - // If both are restricted, then only one needs to match. - {"Sun Jul 15 00:00 2012", "* * 1,15 * Sun", true}, - {"Fri Jun 15 00:00 2012", "* * 1,15 * Sun", true}, - {"Wed Aug 1 00:00 2012", "* * 1,15 * Sun", true}, - {"Sun Jul 15 00:00 2012", "* * */10 * Sun", true}, // verifies #70 - - // However, if one has a star, then both need to match. - {"Sun Jul 15 00:00 2012", "* * * * Mon", false}, - {"Mon Jul 9 00:00 2012", "* * 1,15 * *", false}, - {"Sun Jul 15 00:00 2012", "* * 1,15 * *", true}, - {"Sun Jul 15 00:00 2012", "* * */2 * Sun", true}, - } - - for _, test := range tests { - sched, err := ParseStandard(test.spec) - if err != nil { - t.Error(err) - continue - } - actual := sched.Next(getTime(test.time).Add(-1 * time.Second)) - expected := getTime(test.time) - if test.expected && expected != actual || !test.expected && expected == actual { - t.Errorf("Fail evaluating %s on %s: (expected) %s != %s (actual)", - test.spec, test.time, expected, actual) - } - } -} - -func TestNext(t *testing.T) { - runs := []struct { - time, spec string - expected string - }{ - // Simple cases - {"Mon Jul 9 14:45 2012", "0 0/15 * * * *", "Mon Jul 9 15:00 2012"}, - {"Mon Jul 9 14:59 2012", "0 0/15 * * * *", "Mon Jul 9 15:00 2012"}, - {"Mon Jul 9 14:59:59 2012", "0 0/15 * * * *", "Mon Jul 9 15:00 2012"}, - - // Wrap around hours - {"Mon Jul 9 15:45 2012", "0 20-35/15 * * * *", "Mon Jul 9 16:20 2012"}, - - // Wrap around days - {"Mon Jul 9 23:46 2012", "0 */15 * * * *", "Tue Jul 10 00:00 2012"}, - {"Mon Jul 9 23:45 2012", "0 20-35/15 * * * *", "Tue Jul 10 00:20 2012"}, - {"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * * * *", "Tue Jul 10 00:20:15 2012"}, - {"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 1/2 * * *", "Tue Jul 10 01:20:15 2012"}, - {"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 10-12 * * *", "Tue Jul 10 10:20:15 2012"}, - - {"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 1/2 */2 * *", "Thu Jul 11 01:20:15 2012"}, - {"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * 9-20 * *", "Wed Jul 10 00:20:15 2012"}, - {"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * 9-20 Jul *", "Wed Jul 10 00:20:15 2012"}, - - // Wrap around months - {"Mon Jul 9 23:35 2012", "0 0 0 9 Apr-Oct ?", "Thu Aug 9 00:00 2012"}, - {"Mon Jul 9 23:35 2012", "0 0 0 */5 Apr,Aug,Oct Mon", "Tue Aug 1 00:00 2012"}, - {"Mon Jul 9 23:35 2012", "0 0 0 */5 Oct Mon", "Mon Oct 1 00:00 2012"}, - - // Wrap around years - {"Mon Jul 9 23:35 2012", "0 0 0 * Feb Mon", "Mon Feb 4 00:00 2013"}, - {"Mon Jul 9 23:35 2012", "0 0 0 * Feb Mon/2", "Fri Feb 1 00:00 2013"}, - - // Wrap around minute, hour, day, month, and year - {"Mon Dec 31 23:59:45 2012", "0 * * * * *", "Tue Jan 1 00:00:00 2013"}, - - // Leap year - {"Mon Jul 9 23:35 2012", "0 0 0 29 Feb ?", "Mon Feb 29 00:00 2016"}, - - // Daylight savings time 2am EST (-5) -> 3am EDT (-4) - {"2012-03-11T00:00:00-0500", "TZ=America/New_York 0 30 2 11 Mar ?", "2013-03-11T02:30:00-0400"}, - - // hourly job - {"2012-03-11T00:00:00-0500", "TZ=America/New_York 0 0 * * * ?", "2012-03-11T01:00:00-0500"}, - {"2012-03-11T01:00:00-0500", "TZ=America/New_York 0 0 * * * ?", "2012-03-11T03:00:00-0400"}, - {"2012-03-11T03:00:00-0400", "TZ=America/New_York 0 0 * * * ?", "2012-03-11T04:00:00-0400"}, - {"2012-03-11T04:00:00-0400", "TZ=America/New_York 0 0 * * * ?", "2012-03-11T05:00:00-0400"}, - - // hourly job using CRON_TZ - {"2012-03-11T00:00:00-0500", "CRON_TZ=America/New_York 0 0 * * * ?", "2012-03-11T01:00:00-0500"}, - {"2012-03-11T01:00:00-0500", "CRON_TZ=America/New_York 0 0 * * * ?", "2012-03-11T03:00:00-0400"}, - {"2012-03-11T03:00:00-0400", "CRON_TZ=America/New_York 0 0 * * * ?", "2012-03-11T04:00:00-0400"}, - {"2012-03-11T04:00:00-0400", "CRON_TZ=America/New_York 0 0 * * * ?", "2012-03-11T05:00:00-0400"}, - - // 1am nightly job - {"2012-03-11T00:00:00-0500", "TZ=America/New_York 0 0 1 * * ?", "2012-03-11T01:00:00-0500"}, - {"2012-03-11T01:00:00-0500", "TZ=America/New_York 0 0 1 * * ?", "2012-03-12T01:00:00-0400"}, - - // 2am nightly job (skipped) - {"2012-03-11T00:00:00-0500", "TZ=America/New_York 0 0 2 * * ?", "2012-03-12T02:00:00-0400"}, - - // Daylight savings time 2am EDT (-4) => 1am EST (-5) - {"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 30 2 04 Nov ?", "2012-11-04T02:30:00-0500"}, - {"2012-11-04T01:45:00-0400", "TZ=America/New_York 0 30 1 04 Nov ?", "2012-11-04T01:30:00-0500"}, - - // hourly job - {"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 0 * * * ?", "2012-11-04T01:00:00-0400"}, - {"2012-11-04T01:00:00-0400", "TZ=America/New_York 0 0 * * * ?", "2012-11-04T01:00:00-0500"}, - {"2012-11-04T01:00:00-0500", "TZ=America/New_York 0 0 * * * ?", "2012-11-04T02:00:00-0500"}, - - // 1am nightly job (runs twice) - {"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 0 1 * * ?", "2012-11-04T01:00:00-0400"}, - {"2012-11-04T01:00:00-0400", "TZ=America/New_York 0 0 1 * * ?", "2012-11-04T01:00:00-0500"}, - {"2012-11-04T01:00:00-0500", "TZ=America/New_York 0 0 1 * * ?", "2012-11-05T01:00:00-0500"}, - - // 2am nightly job - {"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 0 2 * * ?", "2012-11-04T02:00:00-0500"}, - {"2012-11-04T02:00:00-0500", "TZ=America/New_York 0 0 2 * * ?", "2012-11-05T02:00:00-0500"}, - - // 3am nightly job - {"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 0 3 * * ?", "2012-11-04T03:00:00-0500"}, - {"2012-11-04T03:00:00-0500", "TZ=America/New_York 0 0 3 * * ?", "2012-11-05T03:00:00-0500"}, - - // hourly job - {"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 * * * ?", "2012-11-04T01:00:00-0400"}, - {"TZ=America/New_York 2012-11-04T01:00:00-0400", "0 0 * * * ?", "2012-11-04T01:00:00-0500"}, - {"TZ=America/New_York 2012-11-04T01:00:00-0500", "0 0 * * * ?", "2012-11-04T02:00:00-0500"}, - - // 1am nightly job (runs twice) - {"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 1 * * ?", "2012-11-04T01:00:00-0400"}, - {"TZ=America/New_York 2012-11-04T01:00:00-0400", "0 0 1 * * ?", "2012-11-04T01:00:00-0500"}, - {"TZ=America/New_York 2012-11-04T01:00:00-0500", "0 0 1 * * ?", "2012-11-05T01:00:00-0500"}, - - // 2am nightly job - {"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 2 * * ?", "2012-11-04T02:00:00-0500"}, - {"TZ=America/New_York 2012-11-04T02:00:00-0500", "0 0 2 * * ?", "2012-11-05T02:00:00-0500"}, - - // 3am nightly job - {"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 3 * * ?", "2012-11-04T03:00:00-0500"}, - {"TZ=America/New_York 2012-11-04T03:00:00-0500", "0 0 3 * * ?", "2012-11-05T03:00:00-0500"}, - - // Unsatisfiable - {"Mon Jul 9 23:35 2012", "0 0 0 30 Feb ?", ""}, - {"Mon Jul 9 23:35 2012", "0 0 0 31 Apr ?", ""}, - - // Monthly job - {"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 3 3 * ?", "2012-12-03T03:00:00-0500"}, - - // Test the scenario of DST resulting in midnight not being a valid time. - // https://github.com/robfig/cron/issues/157 - {"2018-10-17T05:00:00-0400", "TZ=America/Sao_Paulo 0 0 9 10 * ?", "2018-11-10T06:00:00-0500"}, - {"2018-02-14T05:00:00-0500", "TZ=America/Sao_Paulo 0 0 9 22 * ?", "2018-02-22T07:00:00-0500"}, - } - - for _, c := range runs { - sched, err := secondParser.Parse(c.spec) - if err != nil { - t.Error(err) - continue - } - actual := sched.Next(getTime(c.time)) - expected := getTime(c.expected) - if !actual.Equal(expected) { - t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.spec, expected, actual) - } - } -} - -func TestErrors(t *testing.T) { - invalidSpecs := []string{ - "xyz", - "60 0 * * *", - "0 60 * * *", - "0 0 * * XYZ", - } - for _, spec := range invalidSpecs { - _, err := ParseStandard(spec) - if err == nil { - t.Error("expected an error parsing: ", spec) - } - } -} - -func getTime(value string) time.Time { - if value == "" { - return time.Time{} - } - - var location = time.Local - if strings.HasPrefix(value, "TZ=") { - parts := strings.Fields(value) - loc, err := time.LoadLocation(parts[0][len("TZ="):]) - if err != nil { - panic("could not parse location:" + err.Error()) - } - location = loc - value = parts[1] - } - - var layouts = []string{ - "Mon Jan 2 15:04 2006", - "Mon Jan 2 15:04:05 2006", - } - for _, layout := range layouts { - if t, err := time.ParseInLocation(layout, value, location); err == nil { - return t - } - } - if t, err := time.ParseInLocation("2006-01-02T15:04:05-0700", value, location); err == nil { - return t - } - panic("could not parse time value " + value) -} - -func TestNextWithTz(t *testing.T) { - runs := []struct { - time, spec string - expected string - }{ - // Failing tests - {"2016-01-03T13:09:03+0530", "14 14 * * *", "2016-01-03T14:14:00+0530"}, - {"2016-01-03T04:09:03+0530", "14 14 * * ?", "2016-01-03T14:14:00+0530"}, - - // Passing tests - {"2016-01-03T14:09:03+0530", "14 14 * * *", "2016-01-03T14:14:00+0530"}, - {"2016-01-03T14:00:00+0530", "14 14 * * ?", "2016-01-03T14:14:00+0530"}, - } - for _, c := range runs { - sched, err := ParseStandard(c.spec) - if err != nil { - t.Error(err) - continue - } - actual := sched.Next(getTimeTZ(c.time)) - expected := getTimeTZ(c.expected) - if !actual.Equal(expected) { - t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.spec, expected, actual) - } - } -} - -func getTimeTZ(value string) time.Time { - if value == "" { - return time.Time{} - } - t, err := time.Parse("Mon Jan 2 15:04 2006", value) - if err != nil { - t, err = time.Parse("Mon Jan 2 15:04:05 2006", value) - if err != nil { - t, err = time.Parse("2006-01-02T15:04:05-0700", value) - if err != nil { - panic(err) - } - } - } - - return t -} - -// https://github.com/robfig/cron/issues/144 -func TestSlash0NoHang(t *testing.T) { - schedule := "TZ=America/New_York 15/0 * * * *" - _, err := ParseStandard(schedule) - if err == nil { - t.Error("expected an error on 0 increment") - } -} diff --git a/backend/lib/validate/mongo.go b/backend/lib/validate/mongo.go deleted file mode 100644 index 7ef94177..00000000 --- a/backend/lib/validate/mongo.go +++ /dev/null @@ -1,10 +0,0 @@ -package validate - -import ( - "github.com/globalsign/mgo/bson" - "github.com/go-playground/validator/v10" -) - -func MongoID(sl validator.FieldLevel) bool { - return bson.IsObjectIdHex(sl.Field().String()) -} diff --git a/backend/main.go b/backend/main.go index 86dccf0a..8832bad7 100644 --- a/backend/main.go +++ b/backend/main.go @@ -2,24 +2,20 @@ package main import ( "context" - "crawlab/config" - "crawlab/database" - _ "crawlab/docs" - validate2 "crawlab/lib/validate" - "crawlab/middlewares" - "crawlab/model" - "crawlab/routes" - "crawlab/services" - "crawlab/services/challenge" - "crawlab/services/rpc" "github.com/apex/log" + "github.com/crawlab-team/crawlab-core/config" + validate2 "github.com/crawlab-team/crawlab-core/lib/validate" + "github.com/crawlab-team/crawlab-core/middlewares" + "github.com/crawlab-team/crawlab-core/model" + "github.com/crawlab-team/crawlab-core/routes" + "github.com/crawlab-team/crawlab-core/services" + "github.com/crawlab-team/crawlab-core/services/rpc" + "github.com/crawlab-team/crawlab-db" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" "github.com/olivere/elastic/v7" "github.com/spf13/viper" - "github.com/swaggo/gin-swagger" - "github.com/swaggo/gin-swagger/swaggerFiles" "net" "net/http" "os" @@ -29,11 +25,6 @@ import ( "time" ) -var swagHandler gin.HandlerFunc - -func init() { - swagHandler = ginSwagger.WrapHandler(swaggerFiles.Handler) -} func main() { app := gin.New() app.Use(gin.Logger(), gin.Recovery()) @@ -41,10 +32,6 @@ func main() { _ = v.RegisterValidation("bid", validate2.MongoID) } - if swagHandler != nil { - app.GET("/swagger/*any", swagHandler) - } - // 初始化配置 if err := config.InitConfig(""); err != nil { log.Error("init config error:" + err.Error()) @@ -52,7 +39,7 @@ func main() { } log.Info("initialized config successfully") // 初始化Mongodb数据库 - if err := database.InitMongo(); err != nil { + if err := db.InitMongo(); err != nil { log.Error("init mongodb error:" + err.Error()) debug.PrintStack() panic(err) @@ -60,7 +47,7 @@ func main() { log.Info("initialized mongodb successfully") // 初始化Redis数据库 - if err := database.InitRedis(); err != nil { + if err := db.InitRedis(); err != nil { log.Error("init redis error:" + err.Error()) debug.PrintStack() panic(err) @@ -107,14 +94,6 @@ func main() { } log.Info("initialized dependency fetcher successfully") - // 初始化挑战服务 - if err := challenge.InitChallengeService(); err != nil { - log.Error("init challenge service error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized challenge service successfully") - // 初始化清理服务 if err := services.InitCleanService(); err != nil { log.Error("init clean service error:" + err.Error()) @@ -238,13 +217,13 @@ func main() { } // 任务 { - authGroup.GET("/tasks", routes.GetTaskList) // 任务列表 - authGroup.GET("/tasks/:id", routes.GetTask) // 任务详情 - authGroup.PUT("/tasks", routes.PutTask) // 派发任务 - authGroup.PUT("/tasks/batch", routes.PutBatchTasks) // 批量派发任务 - authGroup.DELETE("/tasks/:id", routes.DeleteTask) // 删除任务 - authGroup.DELETE("/tasks", routes.DeleteSelectedTask) // 删除多个任务 - authGroup.DELETE("/tasks_by_status", routes.DeleteTaskByStatus) // 删除指定状态的任务 + authGroup.GET("/tasks", routes.GetTaskList) // 任务列表 + authGroup.GET("/tasks/:id", routes.GetTask) // 任务详情 + authGroup.PUT("/tasks", routes.PutTask) // 派发任务 + authGroup.PUT("/tasks/batch", routes.PutBatchTasks) // 批量派发任务 + authGroup.DELETE("/tasks/:id", routes.DeleteTask) // 删除任务 + authGroup.DELETE("/tasks", routes.DeleteSelectedTask) // 删除多个任务 + //authGroup.DELETE("/tasks_by_status", routes.DeleteTaskByStatus) // 删除指定状态的任务 authGroup.POST("/tasks/:id/cancel", routes.CancelTask) // 取消任务 authGroup.GET("/tasks/:id/log", routes.GetTaskLog) // 任务日志 authGroup.GET("/tasks/:id/error-log", routes.GetTaskErrorLog) // 任务错误日志 @@ -303,11 +282,6 @@ func main() { authGroup.POST("/projects/:id", routes.PostProject) // 新增 authGroup.DELETE("/projects/:id", routes.DeleteProject) // 删除 } - // 挑战 - { - authGroup.GET("/challenges", routes.GetChallengeList) // 挑战列表 - authGroup.POST("/challenges-check", routes.CheckChallengeList) // 检查挑战列表 - } // 操作 { //authGroup.GET("/actions", routes.GetActionList) // 操作列表 @@ -330,12 +304,6 @@ func main() { authGroup.GET("/git/public-key", routes.GetGitSshPublicKey) // 获取 SSH 公钥 authGroup.GET("/git/commits", routes.GetGitCommits) // 获取 Git Commits authGroup.POST("/git/checkout", routes.PostGitCheckout) // 获取 Git Commits - // 爬虫市场 / 仓库 - { - authGroup.GET("/repos", routes.GetRepoList) // 获取仓库列表 - authGroup.GET("/repos/sub-dir", routes.GetRepoSubDirList) // 获取仓库子目录 - authGroup.POST("/repos/download", routes.DownloadRepo) // 下载仓库 - } } } diff --git a/backend/middlewares/auth.go b/backend/middlewares/auth.go deleted file mode 100644 index 8ab27728..00000000 --- a/backend/middlewares/auth.go +++ /dev/null @@ -1,48 +0,0 @@ -package middlewares - -import ( - "crawlab/constants" - "crawlab/routes" - "crawlab/services" - "github.com/gin-gonic/gin" - "net/http" - "strings" -) - -func AuthorizationMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - // 获取token string - tokenStr := c.GetHeader("Authorization") - - // 校验token - user, err := services.CheckToken(tokenStr) - - // 校验失败,返回错误响应 - if err != nil { - c.AbortWithStatusJSON(http.StatusUnauthorized, routes.Response{ - Status: "ok", - Message: "unauthorized", - Error: "unauthorized", - }) - return - } - - // 如果为普通权限,校验请求地址是否符合要求 - if user.Role == constants.RoleNormal { - if strings.HasPrefix(strings.ToLower(c.Request.URL.Path), "/users") { - c.AbortWithStatusJSON(http.StatusUnauthorized, routes.Response{ - Status: "ok", - Message: "unauthorized", - Error: "unauthorized", - }) - return - } - } - - // 设置用户 - c.Set(constants.ContextUser, &user) - - // 校验成功 - c.Next() - } -} diff --git a/backend/middlewares/cors.go b/backend/middlewares/cors.go deleted file mode 100644 index 5397251d..00000000 --- a/backend/middlewares/cors.go +++ /dev/null @@ -1,19 +0,0 @@ -package middlewares - -import "github.com/gin-gonic/gin" - -func CORSMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - c.Writer.Header().Set("Access-Control-Allow-Origin", "*") - c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") - c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") - c.Writer.Header().Set("Access-Control-Allow-Methods", "DELETE, POST, OPTIONS, GET, PUT") - - if c.Request.Method == "OPTIONS" { - c.AbortWithStatus(204) - return - } - - c.Next() - } -} diff --git a/backend/middlewares/es_log.go b/backend/middlewares/es_log.go deleted file mode 100644 index 464a2a0a..00000000 --- a/backend/middlewares/es_log.go +++ /dev/null @@ -1,54 +0,0 @@ -package middlewares - -import ( - "bytes" - "context" - "fmt" - "github.com/gin-gonic/gin" - "github.com/olivere/elastic/v7" - "github.com/satori/go.uuid" - "github.com/spf13/viper" - "strconv" - "time" -) - -func EsLog(ctx context.Context, esClient *elastic.Client) gin.HandlerFunc { - - return func(c *gin.Context) { - // 开始时间 - crawlabIndex := viper.GetString("setting.crawlabLogIndex") - start := time.Now() - // 处理请求 - c.Next() - // 结束时间 - end := time.Now() - //执行时间 - latency := strconv.FormatInt(end.Sub(start).Nanoseconds()/1000, 10) - path := c.Request.URL.Path - - clientIP := c.ClientIP() - method := c.Request.Method - statusCode := strconv.Itoa(c.Writer.Status()) - buf := new(bytes.Buffer) - buf.ReadFrom(c.Request.Body) - b := buf.String() - accessLog := "costTime:" + latency + "ms--" + "StatusCode:" + statusCode + "--" + "Method:" + method + "--" + "ClientIp:" + clientIP + "--" + - "RequestURI:" + path + "--" + "Host:" + c.Request.Host + "--" + "UserAgent--" + c.Request.UserAgent() + "--RequestBody:" + - string(b) - WriteMsg(ctx, crawlabIndex, esClient, time.Now(), accessLog) - } - -} - -// WriteMsg will write the msg and level into es -func WriteMsg(ctx context.Context, crawlabIndex string, es *elastic.Client, when time.Time, msg string) error { - vals := make(map[string]interface{}) - vals["@timestamp"] = when.Format(time.RFC3339) - vals["@msg"] = msg - uid := uuid.NewV4().String() - _, err := es.Index().Index(crawlabIndex).Id(uid).BodyJson(vals).Refresh("wait_for").Do(ctx) - if err != nil { - fmt.Println(err) - } - return err -} diff --git a/backend/mock/base.go b/backend/mock/base.go deleted file mode 100644 index d8b11eb9..00000000 --- a/backend/mock/base.go +++ /dev/null @@ -1,16 +0,0 @@ -package mock - -type Response struct { - Status string `json:"status"` - Message string `json:"message"` - Data interface{} `json:"data"` - Error string `json:"error"` -} - -type ListResponse struct { - Status string `json:"status"` - Message string `json:"message"` - Total int `json:"total"` - Data interface{} `json:"data"` - Error string `json:"error"` -} diff --git a/backend/mock/file.go b/backend/mock/file.go deleted file mode 100644 index addd771a..00000000 --- a/backend/mock/file.go +++ /dev/null @@ -1,8 +0,0 @@ -package mock - -type File struct { - Name string `json:"name"` - Path string `json:"path"` - IsDir bool `json:"is_dir"` - Size int64 `json:"size"` -} diff --git a/backend/mock/node.go b/backend/mock/node.go deleted file mode 100644 index 2d3a978d..00000000 --- a/backend/mock/node.go +++ /dev/null @@ -1,222 +0,0 @@ -package mock - -import ( - "crawlab/entity" - "crawlab/model" - "crawlab/services" - "github.com/apex/log" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" - "time" -) - -var NodeList = []model.Node{ - { - Id: bson.ObjectId("5d429e6c19f7abede924fee2"), - Ip: "10.32.35.15", - Name: "test1", - Status: "online", - Port: "8081", - Mac: "ac:12:df:12:fd", - Description: "For test1", - IsMaster: true, - UpdateTs: time.Now(), - CreateTs: time.Now(), - UpdateTsUnix: time.Now().Unix(), - }, - { - Id: bson.ObjectId("5d429e6c19f7abede924fe22"), - Ip: "10.32.35.12", - Name: "test2", - Status: "online", - Port: "8082", - Mac: "ac:12:df:12:vh", - Description: "For test2", - IsMaster: true, - UpdateTs: time.Now(), - CreateTs: time.Now(), - UpdateTsUnix: time.Now().Unix(), - }, -} - -var TaskList = []model.Task{ - { - Id: "1234", - SpiderId: bson.ObjectId("5d429e6c19f7abede924fee2"), - StartTs: time.Now(), - FinishTs: time.Now(), - Status: "进行中", - NodeId: bson.ObjectId("5d429e6c19f7abede924fee2"), - LogPath: "./log", - Cmd: "scrapy crawl test", - Error: "", - ResultCount: 0, - WaitDuration: 10.0, - RuntimeDuration: 10, - TotalDuration: 20, - SpiderName: "test", - NodeName: "test", - CreateTs: time.Now(), - UpdateTs: time.Now(), - }, - { - Id: "5678", - SpiderId: bson.ObjectId("5d429e6c19f7abede924fee2"), - StartTs: time.Now(), - FinishTs: time.Now(), - Status: "进行中", - NodeId: bson.ObjectId("5d429e6c19f7abede924fee2"), - LogPath: "./log", - Cmd: "scrapy crawl test2", - Error: "", - ResultCount: 0, - WaitDuration: 10.0, - RuntimeDuration: 10, - TotalDuration: 20, - SpiderName: "test", - NodeName: "test", - CreateTs: time.Now(), - UpdateTs: time.Now(), - }, -} - -var dataList = []services.Data{ - { - Mac: "ac:12:fc:fd:ds:dd", - Ip: "192.10.2.1", - Master: true, - UpdateTs: time.Now(), - UpdateTsUnix: time.Now().Unix(), - }, - { - Mac: "22:12:fc:fd:ds:dd", - Ip: "182.10.2.2", - Master: true, - UpdateTs: time.Now(), - UpdateTsUnix: time.Now().Unix(), - }, -} - -var executeble = []entity.Executable{ - { - Path: "/test", - FileName: "test.py", - DisplayName: "test.py", - }, -} -var systemInfo = entity.SystemInfo{ARCH: "x86", - OS: "linux", - Hostname: "test", - NumCpu: 4, - Executables: executeble, -} - -func GetNodeList(c *gin.Context) { - nodes := NodeList - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: nodes, - }) -} - -func GetNode(c *gin.Context) { - var result model.Node - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - for _, node := range NodeList { - if node.Id == bson.ObjectId(id) { - result = node - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: result, - }) -} - -func Ping(c *gin.Context) { - data := dataList[0] - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: data, - }) -} - -func PostNode(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var oldItem model.Node - for _, node := range NodeList { - if node.Id == bson.ObjectId(id) { - oldItem = node - } - - } - log.Info(id) - var newItem model.Node - if err := c.ShouldBindJSON(&newItem); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - newItem.Id = oldItem.Id - - log.Info("Post Node success") - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func GetNodeTaskList(c *gin.Context) { - - tasks := TaskList - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: tasks, - }) -} - -func DeleteNode(c *gin.Context) { - id := bson.ObjectId("5d429e6c19f7abede924fee2") - - for _, node := range NodeList { - if node.Id == id { - log.Infof("Delete a node") - } - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func GetSystemInfo(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - sysInfo := systemInfo - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: sysInfo, - }) -} diff --git a/backend/mock/node_test.go b/backend/mock/node_test.go deleted file mode 100644 index abd568c2..00000000 --- a/backend/mock/node_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package mock - -import ( - "bytes" - "crawlab/model" - "encoding/json" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - . "github.com/smartystreets/goconvey/convey" - "net/http" - "net/http/httptest" - "testing" - "time" -) - -var app *gin.Engine - -// 本测试依赖MongoDB的服务,所以在测试之前需要启动MongoDB及相关服务 -func init() { - app = gin.Default() - - // mock Test - // 节点相关的API - app.GET("/ping", Ping) - app.GET("/nodes", GetNodeList) // 节点列表 - app.GET("/nodes/:id", GetNode) // 节点详情 - app.POST("/nodes/:id", PostNode) // 修改节点 - app.GET("/nodes/:id/tasks", GetNodeTaskList) // 节点任务列表 - app.GET("/nodes/:id/system", GetSystemInfo) // 节点任务列表 - app.DELETE("/nodes/:id", DeleteNode) // 删除节点 - //// 爬虫 - app.GET("/stats/home", GetHomeStats) // 首页统计数据 - // 定时任务 - app.GET("/schedules", GetScheduleList) // 定时任务列表 - app.GET("/schedules/:id", GetSchedule) // 定时任务详情 - app.PUT("/schedules", PutSchedule) // 创建定时任务 - app.POST("/schedules/:id", PostSchedule) // 修改定时任务 - app.DELETE("/schedules/:id", DeleteSchedule) // 删除定时任务 - app.GET("/tasks", GetTaskList) // 任务列表 - app.GET("/tasks/:id", GetTask) // 任务详情 - app.PUT("/tasks", PutTask) // 派发任务 - app.DELETE("/tasks/:id", DeleteTask) // 删除任务 - app.GET("/tasks/:id/results", GetTaskResults) // 任务结果 - app.GET("/tasks/:id/results/download", DownloadTaskResultsCsv) // 下载任务结果 - app.GET("/spiders", GetSpiderList) // 爬虫列表 - app.GET("/spiders/:id", GetSpider) // 爬虫详情 - app.POST("/spiders/:id", PostSpider) // 修改爬虫 - app.DELETE("/spiders/:id", DeleteSpider) // 删除爬虫 - app.GET("/spiders/:id/tasks", GetSpiderTasks) // 爬虫任务列表 - app.GET("/spiders/:id/dir", GetSpiderDir) // 爬虫目录 -} - -//mock test, test data in ./mock -func TestGetNodeList(t *testing.T) { - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/nodes", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - - Convey("Test API GetNodeList", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestGetNode(t *testing.T) { - var resp Response - var mongoId = "5d429e6c19f7abede924fee2" - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/nodes/"+mongoId, nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - t.Log(resp.Data) - Convey("Test API GetNode", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - So(resp.Data.(map[string]interface{})["_id"], ShouldEqual, bson.ObjectId(mongoId).Hex()) - }) - }) -} - -func TestPing(t *testing.T) { - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/ping", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - Convey("Test API ping", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestGetNodeTaskList(t *testing.T) { - var resp Response - var mongoId = "5d429e6c19f7abede924fee2" - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "nodes/"+mongoId+"/tasks", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - Convey("Test API GetNodeTaskList", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestDeleteNode(t *testing.T) { - var resp Response - - var mongoId = "5d429e6c19f7abede924fee2" - w := httptest.NewRecorder() - req, _ := http.NewRequest("DELETE", "nodes/"+mongoId, nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - Convey("Test API DeleteNode", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestPostNode(t *testing.T) { - var newItem = model.Node{ - Id: bson.ObjectIdHex("5d429e6c19f7abede924fee2"), - Ip: "10.32.35.15", - Name: "test1", - Status: "online", - Port: "8081", - Mac: "ac:12:df:12:fd", - Description: "For test1", - IsMaster: true, - UpdateTs: time.Now(), - CreateTs: time.Now(), - UpdateTsUnix: time.Now().Unix(), - } - - var resp Response - body, _ := json.Marshal(newItem) - - var mongoId = "5d429e6c19f7abede924fee2" - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "nodes/"+mongoId, bytes.NewReader(body)) - - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - t.Log(resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - Convey("Test API PostNode", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestGetSystemInfo(t *testing.T) { - var resp Response - var mongoId = "5d429e6c19f7abede924fee2" - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "nodes/"+mongoId+"/system", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - Convey("Test API GetSystemInfo", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} diff --git a/backend/mock/schedule.go b/backend/mock/schedule.go deleted file mode 100644 index e5c45546..00000000 --- a/backend/mock/schedule.go +++ /dev/null @@ -1,136 +0,0 @@ -package mock - -import ( - "crawlab/constants" - "crawlab/model" - "fmt" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" - "time" -) - -var NodeIdss = []bson.ObjectId{bson.ObjectIdHex("5d429e6c19f7abede924fee2"), - bson.ObjectIdHex("5d429e6c19f7abede924fee1")} - -var scheduleList = []model.Schedule{ - { - Id: bson.ObjectId("5d429e6c19f7abede924fee2"), - Name: "test schedule", - SpiderId: "123", - NodeIds: NodeIdss, - Cron: "***1*", - EntryId: 10, - // 前端展示 - SpiderName: "test scedule", - - CreateTs: time.Now(), - UpdateTs: time.Now(), - }, - { - Id: bson.ObjectId("xx429e6c19f7abede924fee2"), - Name: "test schedule2", - SpiderId: "234", - NodeIds: NodeIdss, - Cron: "***1*", - EntryId: 10, - // 前端展示 - SpiderName: "test scedule2", - - CreateTs: time.Now(), - UpdateTs: time.Now(), - }, -} - -func GetScheduleList(c *gin.Context) { - results := scheduleList - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: results, - }) -} - -func GetSchedule(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var result model.Schedule - for _, sch := range scheduleList { - if sch.Id == bson.ObjectId(id) { - result = sch - } - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: result, - }) -} - -func PostSchedule(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var oldItem model.Schedule - for _, sch := range scheduleList { - if sch.Id == bson.ObjectId(id) { - oldItem = sch - } - - } - - var newItem model.Schedule - if err := c.ShouldBindJSON(&newItem); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - newItem.Id = oldItem.Id - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func PutSchedule(c *gin.Context) { - var item model.Schedule - - // 绑定数据模型 - if err := c.ShouldBindJSON(&item); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 如果node_id为空,则置为空ObjectId - for _, NodeId := range item.NodeIds { - if NodeId == "" { - NodeId = bson.ObjectIdHex(constants.ObjectIdNull) - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func DeleteSchedule(c *gin.Context) { - id := bson.ObjectIdHex("5d429e6c19f7abede924fee2") - for _, sch := range scheduleList { - if sch.Id == id { - fmt.Println("delete a schedule") - } - } - fmt.Println(id) - fmt.Println("update schedule") - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/mock/schedule_test.go b/backend/mock/schedule_test.go deleted file mode 100644 index 87f1131a..00000000 --- a/backend/mock/schedule_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package mock - -import ( - "bytes" - "crawlab/model" - "crawlab/utils" - "encoding/json" - "github.com/globalsign/mgo/bson" - . "github.com/smartystreets/goconvey/convey" - "net/http" - "net/http/httptest" - "strings" - "testing" - "time" -) - -func TestGetScheduleList(t *testing.T) { - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/schedules", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - t.Log(resp.Data) - Convey("Test API GetScheduleList", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestGetSchedule(t *testing.T) { - var mongoId = "5d429e6c19f7abede924fee2" - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/schedules/"+mongoId, nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - Convey("Test API GetSchedule", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - So(resp.Data.(map[string]interface{})["_id"], ShouldEqual, bson.ObjectId(mongoId).Hex()) - }) - }) -} - -func TestDeleteSchedule(t *testing.T) { - var mongoId = "5d429e6c19f7abede924fee2" - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("DELETE", "/schedules/"+mongoId, nil) - app.ServeHTTP(w, req) - - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - - Convey("Test DeleteSchedule", t, func() { - Convey("Test resp status", func() { - So(resp.Status, ShouldEqual, "ok") - }) - }) -} - -func TestPostSchedule(t *testing.T) { - var newItem = model.Schedule{ - Id: bson.ObjectIdHex("5d429e6c19f7abede924fee2"), - Name: "test schedule", - SpiderId: bson.ObjectIdHex("5d429e6c19f7abede924fee2"), - NodeIds: NodeIdss, - Cron: "***1*", - EntryId: 10, - // 前端展示 - SpiderName: "test scedule", - - CreateTs: time.Now(), - UpdateTs: time.Now(), - } - - var resp Response - var mongoId = "5d429e6c19f7abede924fee2" - body, _ := json.Marshal(newItem) - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/schedules/"+mongoId, strings.NewReader(utils.BytesToString(body))) - app.ServeHTTP(w, req) - - err := json.Unmarshal(w.Body.Bytes(), &resp) - t.Log(resp) - if err != nil { - t.Fatal("unmarshal resp failed") - } - Convey("Test API PostSchedule", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) - -} - -func TestPutSchedule(t *testing.T) { - var newItem = model.Schedule{ - Id: bson.ObjectIdHex("5d429e6c19f7abede924fee2"), - Name: "test schedule", - SpiderId: bson.ObjectIdHex("5d429e6c19f7abede924fee2"), - NodeIds: NodeIdss, - Cron: "***1*", - EntryId: 10, - // 前端展示 - SpiderName: "test scedule", - - CreateTs: time.Now(), - UpdateTs: time.Now(), - } - - var resp Response - body, _ := json.Marshal(newItem) - w := httptest.NewRecorder() - req, _ := http.NewRequest("PUT", "/schedules", bytes.NewReader(body)) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - t.Log(resp) - if err != nil { - t.Fatal("unmarshal resp failed") - } - Convey("Test API PutSchedule", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) - -} diff --git a/backend/mock/spider.go b/backend/mock/spider.go deleted file mode 100644 index 1994196e..00000000 --- a/backend/mock/spider.go +++ /dev/null @@ -1,187 +0,0 @@ -package mock - -import ( - "crawlab/constants" - "crawlab/model" - "github.com/apex/log" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "time" -) - -var SpiderList = []model.Spider{ - { - Id: bson.ObjectId("5d429e6c19f7abede924fee2"), - Name: "For test", - DisplayName: "test", - Type: "test", - Col: "test", - Site: "www.baidu.com", - Envs: nil, - Src: "../app/spiders", - Cmd: "scrapy crawl test", - LastRunTs: time.Now(), - CreateTs: time.Now(), - UpdateTs: time.Now(), - UserId: constants.ObjectIdNull, - }, -} - -func GetSpiderList(c *gin.Context) { - - // mock get spider list from database - results := SpiderList - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: results, - }) -} - -func GetSpider(c *gin.Context) { - id := c.Param("id") - var result model.Spider - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - for _, spider := range SpiderList { - if spider.Id == bson.ObjectId(id) { - result = spider - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: result, - }) -} - -func PostSpider(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - } - - var item model.Spider - if err := c.ShouldBindJSON(&item); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - log.Info("modify the item") - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} -func GetSpiderDir(c *gin.Context) { - // 爬虫ID - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 目录相对路径 - path := c.Query("path") - var spi model.Spider - - // 获取爬虫 - for _, spider := range SpiderList { - if spider.Id == bson.ObjectId(id) { - spi = spider - } - } - - // 获取目录下文件列表 - f, err := ioutil.ReadDir(filepath.Join(spi.Src, path)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 遍历文件列表 - var fileList []model.File - for _, file := range f { - fileList = append(fileList, model.File{ - Name: file.Name(), - IsDir: file.IsDir(), - Size: file.Size(), - Path: filepath.Join(path, file.Name()), - }) - } - - // 返回结果 - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: fileList, - }) -} - -func GetSpiderTasks(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var spider model.Spider - for _, spi := range SpiderList { - if spi.Id == bson.ObjectId(id) { - spider = spi - } - } - - var tasks model.Task - for _, task := range TaskList { - if task.SpiderId == spider.Id { - tasks = task - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: tasks, - }) -} - -func DeleteSpider(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - // 获取该爬虫,get this spider - var spider model.Spider - for _, spi := range SpiderList { - if spi.Id == bson.ObjectId(id) { - spider = spi - } - } - - // 删除爬虫文件目录,delete the spider dir - if err := os.RemoveAll(spider.Src); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 从数据库中删除该爬虫,delete this spider from database - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/mock/spider_test.go b/backend/mock/spider_test.go deleted file mode 100644 index 11e2c9cd..00000000 --- a/backend/mock/spider_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package mock - -import ( - "bytes" - "crawlab/constants" - "crawlab/model" - "encoding/json" - "github.com/globalsign/mgo/bson" - . "github.com/smartystreets/goconvey/convey" - "net/http" - "net/http/httptest" - "testing" - "time" -) - -func TestGetSpiderList(t *testing.T) { - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/spiders", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("unmarshal resp faild") - } - Convey("Test API GetSpiderList", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestGetSpider(t *testing.T) { - var resp Response - var spiderId = "5d429e6c19f7abede924fee2" - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/spiders/"+spiderId, nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("unmarshal resp failed") - } - Convey("Test API GetSpider", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestPostSpider(t *testing.T) { - var spider = model.Spider{ - Id: bson.ObjectIdHex("5d429e6c19f7abede924fee2"), - Name: "For test", - DisplayName: "test", - Type: "test", - Col: "test", - Site: "www.baidu.com", - Envs: nil, - Src: "/app/spider", - Cmd: "scrapy crawl test", - LastRunTs: time.Now(), - CreateTs: time.Now(), - UpdateTs: time.Now(), - UserId: constants.ObjectIdNull, - } - var resp Response - var spiderId = "5d429e6c19f7abede924fee2" - w := httptest.NewRecorder() - body, _ := json.Marshal(spider) - req, _ := http.NewRequest("POST", "/spiders/"+spiderId, bytes.NewReader(body)) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("unmarshal resp failed") - } - Convey("Test API PostSpider", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) - -} - -func TestGetSpiderDir(t *testing.T) { - var spiderId = "5d429e6c19f7abede924fee2" - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/spiders/"+spiderId+"/dir", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("unmarshal resp failed") - } - Convey("Test API GetSpiderDir", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) - -} - -func TestGetSpiderTasks(t *testing.T) { - var spiderId = "5d429e6c19f7abede924fee2" - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/spiders/"+spiderId+"/tasks", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("unmarshal resp failed") - } - Convey("Test API GetSpiderTasks", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestDeleteSpider(t *testing.T) { - var spiderId = "5d429e6c19f7abede924fee2" - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("DELETE", "/spiders/"+spiderId, nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("unmarshal resp failed") - } - Convey("Test API DeleteSpider", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} diff --git a/backend/mock/stats.go b/backend/mock/stats.go deleted file mode 100644 index f0227da9..00000000 --- a/backend/mock/stats.go +++ /dev/null @@ -1,62 +0,0 @@ -package mock - -import ( - "crawlab/model" - "github.com/gin-gonic/gin" - "net/http" -) - -var taskDailyItems = []model.TaskDailyItem{ - { - Date: "2019/08/19", - TaskCount: 2, - AvgRuntimeDuration: 1000, - }, - { - Date: "2019/08/20", - TaskCount: 3, - AvgRuntimeDuration: 10130, - }, -} - -func GetHomeStats(c *gin.Context) { - type DataOverview struct { - TaskCount int `json:"task_count"` - SpiderCount int `json:"spider_count"` - ActiveNodeCount int `json:"active_node_count"` - ScheduleCount int `json:"schedule_count"` - } - - type Data struct { - Overview DataOverview `json:"overview"` - Daily []model.TaskDailyItem `json:"daily"` - } - - // 任务总数 - taskCount := 10 - - // 在线节点总数 - activeNodeCount := 4 - - // 爬虫总数 - spiderCount := 5 - // 定时任务数 - scheduleCount := 2 - - // 每日任务数 - items := taskDailyItems - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: Data{ - Overview: DataOverview{ - ActiveNodeCount: activeNodeCount, - TaskCount: taskCount, - SpiderCount: spiderCount, - ScheduleCount: scheduleCount, - }, - Daily: items, - }, - }) -} diff --git a/backend/mock/stats_test.go b/backend/mock/stats_test.go deleted file mode 100644 index a94e52d4..00000000 --- a/backend/mock/stats_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package mock - -import ( - "encoding/json" - "fmt" - . "github.com/smartystreets/goconvey/convey" - "net/http" - "net/http/httptest" - "testing" -) - -func TestGetHomeStats(t *testing.T) { - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/stats/home", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - fmt.Println(resp.Data) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - - Convey("Test API GetHomeStats", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} diff --git a/backend/mock/system.go b/backend/mock/system.go deleted file mode 100644 index f33e02ba..00000000 --- a/backend/mock/system.go +++ /dev/null @@ -1 +0,0 @@ -package mock diff --git a/backend/mock/task.go b/backend/mock/task.go deleted file mode 100644 index 3a2c8fcd..00000000 --- a/backend/mock/task.go +++ /dev/null @@ -1,236 +0,0 @@ -package mock - -import ( - "bytes" - "crawlab/constants" - "crawlab/model" - "crawlab/utils" - "encoding/csv" - "fmt" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "github.com/satori/go.uuid" - "net/http" -) - -type TaskListRequestData struct { - PageNum int `form:"page_num"` - PageSize int `form:"page_size"` - NodeId string `form:"node_id"` - SpiderId string `form:"spider_id"` -} - -type TaskResultsRequestData struct { - PageNum int `form:"page_num"` - PageSize int `form:"page_size"` -} - -func GetTaskList(c *gin.Context) { - // 绑定数据 - data := TaskListRequestData{} - - if err := c.ShouldBindQuery(&data); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - if data.PageNum == 0 { - data.PageNum = 1 - } - if data.PageSize == 0 { - data.PageNum = 10 - } - - // 过滤条件 - query := bson.M{} - if data.NodeId != "" { - query["node_id"] = bson.ObjectIdHex(data.NodeId) - } - if data.SpiderId != "" { - query["spider_id"] = bson.ObjectIdHex(data.SpiderId) - } - - // 获取任务列表 - tasks := TaskList - - // 获取总任务数 - total := len(TaskList) - - c.JSON(http.StatusOK, ListResponse{ - Status: "ok", - Message: "success", - Total: total, - Data: tasks, - }) -} - -func GetTask(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var result model.Task - for _, task := range TaskList { - if task.Id == id { - result = task - } - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: result, - }) -} - -func PutTask(c *gin.Context) { - // 生成任务ID,generate task ID - id := uuid.NewV4() - - // 绑定数据 - var t model.Task - if err := c.ShouldBindJSON(&t); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - t.Id = id.String() - t.Status = constants.StatusPending - - // 如果没有传入node_id,则置为null - if t.NodeId.Hex() == "" { - t.NodeId = bson.ObjectIdHex(constants.ObjectIdNull) - } - - // 将任务存入数据库,put the task into database - fmt.Println("put the task into database") - - // 加入任务队列, put the task into task queue - fmt.Println("put the task into task queue") - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func DeleteTask(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - for _, task := range TaskList { - if task.Id == id { - fmt.Println("delete the task") - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func GetTaskResults(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 绑定数据 - data := TaskResultsRequestData{} - if err := c.ShouldBindQuery(&data); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 获取任务 - var task model.Task - for _, ta := range TaskList { - if ta.Id == id { - task = ta - } - } - - fmt.Println(task) - // 获取结果 - var results interface{} - total := len(TaskList) - - c.JSON(http.StatusOK, ListResponse{ - Status: "ok", - Message: "success", - Data: results, - Total: total, - }) -} - -func DownloadTaskResultsCsv(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 获取任务 - var task model.Task - for _, ta := range TaskList { - if ta.Id == id { - task = ta - } - } - fmt.Println(task) - - // 获取结果 - var results []interface { - } - - // 字段列表 - var columns []string - if len(results) == 0 { - columns = []string{} - } else { - item := results[0].(bson.M) - for key := range item { - columns = append(columns, key) - } - } - - // 缓冲 - bytesBuffer := &bytes.Buffer{} - - // 写入UTF-8 BOM,避免使用Microsoft Excel打开乱码 - bytesBuffer.WriteString("\xEF\xBB\xBF") - - writer := csv.NewWriter(bytesBuffer) - - // 写入表头 - if err := writer.Write(columns); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 写入内容 - for _, result := range results { - // 将result转换为[]string - item := result.(bson.M) - var values []string - for _, col := range columns { - value := utils.InterfaceToString(item[col]) - values = append(values, value) - } - - // 写入数据 - if err := writer.Write(values); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 此时才会将缓冲区数据写入 - writer.Flush() - - // 设置下载的文件名 - c.Writer.Header().Set("Content-Disposition", "attachment;filename=data.csv") - - // 设置文件类型以及输出数据 - c.Data(http.StatusOK, "text/csv", bytesBuffer.Bytes()) -} diff --git a/backend/mock/task_test.go b/backend/mock/task_test.go deleted file mode 100644 index 1cd4ccfa..00000000 --- a/backend/mock/task_test.go +++ /dev/null @@ -1,138 +0,0 @@ -package mock - -import ( - "bytes" - "crawlab/model" - "encoding/json" - "github.com/globalsign/mgo/bson" - . "github.com/smartystreets/goconvey/convey" - "net/http" - "net/http/httptest" - "testing" - "time" -) - -func TestGetTaskList(t *testing.T) { - //var teskListRequestFrom = TaskListRequestData{ - // PageNum: 2, - // PageSize: 10, - // NodeId: "434221grfsf", - // SpiderId: "fdfewqrftea", - //} - - var resp ListResponse - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/tasks?PageNum=2&PageSize=10&NodeId=342dfsff&SpiderId=f8dsf", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - - Convey("Test API GetNodeList", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - So(resp.Total, ShouldEqual, 2) - }) - }) -} - -func TestGetTask(t *testing.T) { - var resp Response - var taskId = "1234" - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/tasks/"+taskId, nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - Convey("Test API GetTask", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestPutTask(t *testing.T) { - var newItem = model.Task{ - Id: "1234", - SpiderId: bson.ObjectIdHex("5d429e6c19f7abede924fee2"), - StartTs: time.Now(), - FinishTs: time.Now(), - Status: "online", - NodeId: bson.ObjectIdHex("5d429e6c19f7abede924fee2"), - LogPath: "./log", - Cmd: "scrapy crawl test", - Error: "", - ResultCount: 0, - WaitDuration: 10.0, - RuntimeDuration: 10, - TotalDuration: 20, - SpiderName: "test", - NodeName: "test", - CreateTs: time.Now(), - UpdateTs: time.Now(), - } - - var resp Response - body, _ := json.Marshal(&newItem) - w := httptest.NewRecorder() - req, _ := http.NewRequest("PUT", "/tasks", bytes.NewReader(body)) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("unmarshal resp failed") - } - Convey("Test API PutTask", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestDeleteTask(t *testing.T) { - taskId := "1234" - var resp Response - w := httptest.NewRecorder() - req, _ := http.NewRequest("DELETE", "/tasks/"+taskId, nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("unmarshal resp failed") - } - Convey("Test API DeleteTask", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - }) - }) -} - -func TestGetTaskResults(t *testing.T) { - //var teskListResultFrom = TaskResultsRequestData{ - // PageNum: 2, - // PageSize: 1, - //} - taskId := "1234" - - var resp ListResponse - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/tasks/"+taskId+"/results?PageNum=2&PageSize=1", nil) - app.ServeHTTP(w, req) - err := json.Unmarshal(w.Body.Bytes(), &resp) - if err != nil { - t.Fatal("Unmarshal resp failed") - } - - Convey("Test API GetNodeList", t, func() { - Convey("Test response status", func() { - So(resp.Status, ShouldEqual, "ok") - So(resp.Message, ShouldEqual, "success") - So(resp.Total, ShouldEqual, 2) - }) - }) -} diff --git a/backend/mock/user.go b/backend/mock/user.go deleted file mode 100644 index f33e02ba..00000000 --- a/backend/mock/user.go +++ /dev/null @@ -1 +0,0 @@ -package mock diff --git a/backend/mock/utils.go b/backend/mock/utils.go deleted file mode 100644 index fd7d4efd..00000000 --- a/backend/mock/utils.go +++ /dev/null @@ -1,24 +0,0 @@ -package mock - -import ( - "github.com/gin-gonic/gin" - "runtime/debug" -) - -func HandleError(statusCode int, c *gin.Context, err error) { - debug.PrintStack() - c.JSON(statusCode, Response{ - Status: "ok", - Message: "error", - Error: err.Error(), - }) -} - -func HandleErrorF(statusCode int, c *gin.Context, err string) { - debug.PrintStack() - c.JSON(statusCode, Response{ - Status: "ok", - Message: "error", - Error: err, - }) -} diff --git a/backend/model/action.go b/backend/model/action.go deleted file mode 100644 index 15406181..00000000 --- a/backend/model/action.go +++ /dev/null @@ -1,162 +0,0 @@ -package model - -import ( - "crawlab/constants" - "crawlab/database" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "runtime/debug" - "time" -) - -type Action struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - UserId bson.ObjectId `json:"user_id" bson:"user_id"` - Type string `json:"type" bson:"type"` - - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` -} - -func (a *Action) Save() error { - s, c := database.GetCol("actions") - defer s.Close() - - a.UpdateTs = time.Now() - - if err := c.UpdateId(a.Id, a); err != nil { - debug.PrintStack() - return err - } - return nil -} - -func (a *Action) Add() error { - s, c := database.GetCol("actions") - defer s.Close() - - a.Id = bson.NewObjectId() - a.UpdateTs = time.Now() - a.CreateTs = time.Now() - if err := c.Insert(a); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func GetAction(id bson.ObjectId) (Action, error) { - s, c := database.GetCol("actions") - defer s.Close() - var user Action - if err := c.Find(bson.M{"_id": id}).One(&user); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return user, err - } - return user, nil -} - -func GetActionList(filter interface{}, skip int, limit int, sortKey string) ([]Action, error) { - s, c := database.GetCol("actions") - defer s.Close() - - var actions []Action - if err := c.Find(filter).Skip(skip).Limit(limit).Sort(sortKey).All(&actions); err != nil { - debug.PrintStack() - return actions, err - } - return actions, nil -} - -func GetActionListTotal(filter interface{}) (int, error) { - s, c := database.GetCol("actions") - defer s.Close() - - var result int - result, err := c.Find(filter).Count() - if err != nil { - return result, err - } - return result, nil -} - -func GetVisitDays(uid bson.ObjectId) (int, error) { - type ResData struct { - Days int `json:"days" bson:"days"` - } - s, c := database.GetCol("actions") - defer s.Close() - - pipeline := []bson.M{ - { - "$match": bson.M{ - "user_id": uid, - "type": constants.ActionTypeVisit, - }, - }, - { - "$addFields": bson.M{ - "date": bson.M{ - "$dateToString": bson.M{ - "format": "%Y%m%d", - "date": "$create_ts", - "timezone": "Asia/Shanghai", - }, - }, - }, - }, - { - "$group": bson.M{ - "_id": "$date", - }, - }, - { - "_id": nil, - "days": bson.M{"$sum": 1}, - }, - } - - var resData []ResData - if err := c.Pipe(pipeline).All(&resData); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return 0, err - } - - return resData[0].Days, nil -} - -func UpdateAction(id bson.ObjectId, item Action) error { - s, c := database.GetCol("actions") - defer s.Close() - - var result Action - if err := c.FindId(id).One(&result); err != nil { - debug.PrintStack() - return err - } - - if err := item.Save(); err != nil { - return err - } - return nil -} - -func RemoveAction(id bson.ObjectId) error { - s, c := database.GetCol("actions") - defer s.Close() - - var result Action - if err := c.FindId(id).One(&result); err != nil { - return err - } - - if err := c.RemoveId(id); err != nil { - return err - } - - return nil -} diff --git a/backend/model/base.go b/backend/model/base.go deleted file mode 100644 index 70d031f3..00000000 --- a/backend/model/base.go +++ /dev/null @@ -1,12 +0,0 @@ -package model - -type Base struct { -} - -func (b *Base) Save() error { - return nil -} - -func (b *Base) Delete() error { - return nil -} diff --git a/backend/model/challenge.go b/backend/model/challenge.go deleted file mode 100644 index 09f4db89..00000000 --- a/backend/model/challenge.go +++ /dev/null @@ -1,187 +0,0 @@ -package model - -import ( - "crawlab/database" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "runtime/debug" - "time" -) - -type Challenge struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - Name string `json:"name" bson:"name"` - TitleCn string `json:"title_cn" bson:"title_cn"` - TitleEn string `json:"title_en" bson:"title_en"` - DescriptionCn string `json:"description_cn" bson:"description_cn"` - DescriptionEn string `json:"description_en" bson:"description_en"` - Difficulty int `json:"difficulty" bson:"difficulty"` - Path string `json:"path" bson:"path"` - - // 前端展示 - Achieved bool `json:"achieved" bson:"achieved"` - - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` -} - -func (ch *Challenge) Save() error { - s, c := database.GetCol("challenges") - defer s.Close() - - ch.UpdateTs = time.Now() - - if err := c.UpdateId(ch.Id, ch); err != nil { - debug.PrintStack() - return err - } - return nil -} - -func (ch *Challenge) Add() error { - s, c := database.GetCol("challenges") - defer s.Close() - - ch.Id = bson.NewObjectId() - ch.UpdateTs = time.Now() - ch.CreateTs = time.Now() - if err := c.Insert(ch); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func GetChallenge(id bson.ObjectId) (Challenge, error) { - s, c := database.GetCol("challenges") - defer s.Close() - - var ch Challenge - if err := c.Find(bson.M{"_id": id}).One(&ch); err != nil { - if err != mgo.ErrNotFound { - log.Errorf(err.Error()) - debug.PrintStack() - return ch, err - } - } - - return ch, nil -} - -func GetChallengeByName(name string) (Challenge, error) { - s, c := database.GetCol("challenges") - defer s.Close() - - var ch Challenge - if err := c.Find(bson.M{"name": name}).One(&ch); err != nil { - if err != mgo.ErrNotFound { - log.Errorf(err.Error()) - debug.PrintStack() - return ch, err - } - } - - return ch, nil -} - -func GetChallengeList(filter interface{}, skip int, limit int, sortKey string) ([]Challenge, error) { - s, c := database.GetCol("challenges") - defer s.Close() - - var challenges []Challenge - if err := c.Find(filter).Skip(skip).Limit(limit).Sort(sortKey).All(&challenges); err != nil { - debug.PrintStack() - return challenges, err - } - - return challenges, nil -} - -func GetChallengeListWithAchieved(filter interface{}, skip int, limit int, sortKey string, uid bson.ObjectId) ([]Challenge, error) { - challenges, err := GetChallengeList(filter, skip, limit, sortKey) - if err != nil { - return challenges, err - } - - for i, ch := range challenges { - query := bson.M{ - "user_id": uid, - "challenge_id": ch.Id, - } - - list, err := GetChallengeAchievementList(query, 0, 1, "-_id") - if err != nil { - continue - } - - challenges[i].Achieved = len(list) > 0 - } - - return challenges, nil -} - -func GetChallengeListTotal(filter interface{}) (int, error) { - s, c := database.GetCol("challenges") - defer s.Close() - - var result int - result, err := c.Find(filter).Count() - if err != nil { - return result, err - } - return result, nil -} - -type ChallengeAchievement struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - ChallengeId bson.ObjectId `json:"challenge_id" bson:"challenge_id"` - UserId bson.ObjectId `json:"user_id" bson:"user_id"` - - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` -} - -func (ca *ChallengeAchievement) Save() error { - s, c := database.GetCol("challenges_achievements") - defer s.Close() - - ca.UpdateTs = time.Now() - - if err := c.UpdateId(ca.Id, c); err != nil { - debug.PrintStack() - return err - } - return nil -} - -func (ca *ChallengeAchievement) Add() error { - s, c := database.GetCol("challenges_achievements") - defer s.Close() - - ca.Id = bson.NewObjectId() - ca.UpdateTs = time.Now() - ca.CreateTs = time.Now() - if err := c.Insert(ca); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func GetChallengeAchievementList(filter interface{}, skip int, limit int, sortKey string) ([]ChallengeAchievement, error) { - s, c := database.GetCol("challenges_achievements") - defer s.Close() - - var challengeAchievements []ChallengeAchievement - if err := c.Find(filter).Skip(skip).Limit(limit).Sort(sortKey).All(&challengeAchievements); err != nil { - debug.PrintStack() - return challengeAchievements, err - } - - return challengeAchievements, nil -} diff --git a/backend/model/config_spider/common.go b/backend/model/config_spider/common.go deleted file mode 100644 index 4d244fe1..00000000 --- a/backend/model/config_spider/common.go +++ /dev/null @@ -1,26 +0,0 @@ -package config_spider - -import "crawlab/entity" - -func GetAllFields(data entity.ConfigSpiderData) []entity.Field { - var fields []entity.Field - for _, stage := range data.Stages { - for _, field := range stage.Fields { - fields = append(fields, field) - } - } - return fields -} - -func GetStartStageName(data entity.ConfigSpiderData) string { - // 如果 start_stage 设置了且在 stages 里,则返回 - if data.StartStage != "" { - return data.StartStage - } - - // 否则返回第一个 stage - for _, stage := range data.Stages { - return stage.Name - } - return "" -} diff --git a/backend/model/config_spider/scrapy.go b/backend/model/config_spider/scrapy.go deleted file mode 100644 index cbdf4a09..00000000 --- a/backend/model/config_spider/scrapy.go +++ /dev/null @@ -1,263 +0,0 @@ -package config_spider - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/model" - "crawlab/utils" - "errors" - "fmt" - "path/filepath" -) - -type ScrapyGenerator struct { - Spider model.Spider - ConfigData entity.ConfigSpiderData -} - -// 生成爬虫文件 -func (g ScrapyGenerator) Generate() error { - // 生成 items.py - if err := g.ProcessItems(); err != nil { - return err - } - - // 生成 spider.py - if err := g.ProcessSpider(); err != nil { - return err - } - return nil -} - -// 生成 items.py -func (g ScrapyGenerator) ProcessItems() error { - // 待处理文件名 - src := g.Spider.Src - filePath := filepath.Join(src, "config_spider", "items.py") - - // 获取所有字段 - fields := g.GetAllFields() - - // 字段名列表(包含默认字段名) - fieldNames := []string{ - "_id", - "task_id", - "ts", - } - - // 加入字段 - for _, field := range fields { - fieldNames = append(fieldNames, field.Name) - } - - // 将字段名转化为python代码 - str := "" - for _, fieldName := range fieldNames { - line := g.PadCode(fmt.Sprintf("%s = scrapy.Field()", fieldName), 1) - str += line - } - - // 将占位符替换为代码 - if err := utils.SetFileVariable(filePath, constants.AnchorItems, str); err != nil { - return err - } - - return nil -} - -// 生成 spider.py -func (g ScrapyGenerator) ProcessSpider() error { - // 待处理文件名 - src := g.Spider.Src - filePath := filepath.Join(src, "config_spider", "spiders", "spider.py") - - // 替换 start_stage - if err := utils.SetFileVariable(filePath, constants.AnchorStartStage, "parse_"+GetStartStageName(g.ConfigData)); err != nil { - return err - } - - // 替换 start_url - if err := utils.SetFileVariable(filePath, constants.AnchorStartUrl, g.ConfigData.StartUrl); err != nil { - return err - } - - // 替换 parsers - strParser := "" - for _, stage := range g.ConfigData.Stages { - stageName := stage.Name - stageStr := g.GetParserString(stageName, stage) - strParser += stageStr - } - if err := utils.SetFileVariable(filePath, constants.AnchorParsers, strParser); err != nil { - return err - } - - return nil -} - -func (g ScrapyGenerator) GetParserString(stageName string, stage entity.Stage) string { - // 构造函数定义行 - strDef := g.PadCode(fmt.Sprintf("def parse_%s(self, response):", stageName), 1) - - strParse := "" - if stage.IsList { - // 列表逻辑 - strParse = g.GetListParserString(stageName, stage) - } else { - // 非列表逻辑 - strParse = g.GetNonListParserString(stageName, stage) - } - - // 构造 - str := fmt.Sprintf(`%s%s`, strDef, strParse) - - return str -} - -func (g ScrapyGenerator) PadCode(str string, num int) string { - res := "" - for i := 0; i < num; i++ { - res += " " - } - res += str - res += "\n" - return res -} - -func (g ScrapyGenerator) GetNonListParserString(stageName string, stage entity.Stage) string { - str := "" - - // 获取或构造item - str += g.PadCode("item = Item() if response.meta.get('item') is None else response.meta.get('item')", 2) - - // 遍历字段列表 - for _, f := range stage.Fields { - line := fmt.Sprintf(`item['%s'] = response.%s.extract_first()`, f.Name, g.GetExtractStringFromField(f)) - line = g.PadCode(line, 2) - str += line - } - - // next stage 字段 - if f, err := g.GetNextStageField(stage); err == nil { - // 如果找到 next stage 字段,进行下一个回调 - str += g.PadCode(fmt.Sprintf(`yield scrapy.Request(url="get_real_url(response, item['%s'])", callback=self.parse_%s, meta={'item': item})`, f.Name, f.NextStage), 2) - } else { - // 如果没找到 next stage 字段,返回 item - str += g.PadCode(fmt.Sprintf(`yield item`), 2) - } - - // 加入末尾换行 - str += g.PadCode("", 0) - - return str -} - -func (g ScrapyGenerator) GetListParserString(stageName string, stage entity.Stage) string { - str := "" - - // 获取前一个 stage 的 item - str += g.PadCode(`prev_item = response.meta.get('item')`, 2) - - // for 循环遍历列表 - str += g.PadCode(fmt.Sprintf(`for elem in response.%s:`, g.GetListString(stage)), 2) - - // 构造item - str += g.PadCode(`item = Item()`, 3) - - // 遍历字段列表 - for _, f := range stage.Fields { - line := fmt.Sprintf(`item['%s'] = elem.%s.extract_first()`, f.Name, g.GetExtractStringFromField(f)) - line = g.PadCode(line, 3) - str += line - } - - // 把前一个 stage 的 item 值赋给当前 item - str += g.PadCode(`if prev_item is not None:`, 3) - str += g.PadCode(`for key, value in prev_item.items():`, 4) - str += g.PadCode(`item[key] = value`, 5) - - // next stage 字段 - if f, err := g.GetNextStageField(stage); err == nil { - // 如果 url 为空,则不进入下一个 stage - str += g.PadCode(fmt.Sprintf(`if not item['%s']:`, f.Name), 3) - str += g.PadCode(`continue`, 4) - - // 如果找到 next stage 字段,进行下一个回调 - str += g.PadCode(fmt.Sprintf(`yield scrapy.Request(url=get_real_url(response, item['%s']), callback=self.parse_%s, meta={'item': item})`, f.Name, f.NextStage), 3) - } else { - // 如果没找到 next stage 字段,返回 item - str += g.PadCode(fmt.Sprintf(`yield item`), 3) - } - - // 分页 - if stage.PageCss != "" || stage.PageXpath != "" { - str += g.PadCode(fmt.Sprintf(`next_url = response.%s.extract_first()`, g.GetExtractStringFromStage(stage)), 2) - str += g.PadCode(fmt.Sprintf(`yield scrapy.Request(url=get_real_url(response, next_url), callback=self.parse_%s, meta={'item': prev_item})`, stageName), 2) - } - - // 加入末尾换行 - str += g.PadCode("", 0) - - return str -} - -// 获取所有字段 -func (g ScrapyGenerator) GetAllFields() []entity.Field { - return GetAllFields(g.ConfigData) -} - -// 获取包含 next stage 的字段 -func (g ScrapyGenerator) GetNextStageField(stage entity.Stage) (entity.Field, error) { - for _, field := range stage.Fields { - if field.NextStage != "" { - return field, nil - } - } - return entity.Field{}, errors.New("cannot find next stage field") -} - -func (g ScrapyGenerator) GetExtractStringFromField(f entity.Field) string { - if f.Css != "" { - // 如果为CSS - if f.Attr == "" { - // 文本 - return fmt.Sprintf(`css('%s::text')`, f.Css) - } else { - // 属性 - return fmt.Sprintf(`css('%s::attr("%s")')`, f.Css, f.Attr) - } - } else { - // 如果为XPath - if f.Attr == "" { - // 文本 - return fmt.Sprintf(`xpath('string(%s)')`, f.Xpath) - } else { - // 属性 - return fmt.Sprintf(`xpath('%s/@%s')`, f.Xpath, f.Attr) - } - } -} - -func (g ScrapyGenerator) GetExtractStringFromStage(stage entity.Stage) string { - // 分页元素属性,默认为 href - pageAttr := "href" - if stage.PageAttr != "" { - pageAttr = stage.PageAttr - } - - if stage.PageCss != "" { - // 如果为CSS - return fmt.Sprintf(`css('%s::attr("%s")')`, stage.PageCss, pageAttr) - } else { - // 如果为XPath - return fmt.Sprintf(`xpath('%s/@%s')`, stage.PageXpath, pageAttr) - } -} - -func (g ScrapyGenerator) GetListString(stage entity.Stage) string { - if stage.ListCss != "" { - return fmt.Sprintf(`css('%s')`, stage.ListCss) - } else { - return fmt.Sprintf(`xpath('%s')`, stage.ListXpath) - } -} diff --git a/backend/model/file.go b/backend/model/file.go deleted file mode 100644 index a2ad34eb..00000000 --- a/backend/model/file.go +++ /dev/null @@ -1,78 +0,0 @@ -package model - -import ( - "crawlab/database" - "crawlab/utils" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "os" - "runtime/debug" - "time" -) - -type GridFs struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - ChunkSize int32 `json:"chunk_size" bson:"chunkSize"` - UploadDate time.Time `json:"upload_date" bson:"uploadDate"` - Length int32 `json:"length" bson:"length"` - Md5 string `json:"md_5" bson:"md5"` - Filename string `json:"filename" bson:"filename"` -} - -type File struct { - Name string `json:"name"` - Path string `json:"path"` - RelativePath string `json:"relative_path"` - IsDir bool `json:"is_dir"` - Size int64 `json:"size"` - Children []File `json:"children"` - Label string `json:"label"` -} - -func (f *GridFs) Remove() { - s, gf := database.GetGridFs("files") - defer s.Close() - if err := gf.RemoveId(f.Id); err != nil { - log.Errorf("remove file id error: %s, id: %s", err.Error(), f.Id.Hex()) - debug.PrintStack() - } -} - -func GetAllGridFs() []*GridFs { - s, gf := database.GetGridFs("files") - defer s.Close() - - var files []*GridFs - if err := gf.Find(nil).All(&files); err != nil { - log.Errorf("get all files error: {}", err.Error()) - debug.PrintStack() - return nil - } - return files -} - -func GetGridFs(id bson.ObjectId) *GridFs { - s, gf := database.GetGridFs("files") - defer s.Close() - - var gfFile GridFs - err := gf.Find(bson.M{"_id": id}).One(&gfFile) - if err != nil { - log.Errorf("get gf file error: %s, file_id: %s", err.Error(), id.Hex()) - debug.PrintStack() - return nil - } - return &gfFile -} - -func RemoveFile(path string) error { - if !utils.Exists(path) { - log.Info("file not found: " + path) - debug.PrintStack() - return nil - } - if err := os.RemoveAll(path); err != nil { - return err - } - return nil -} diff --git a/backend/model/log.go b/backend/model/log.go deleted file mode 100644 index fecf7def..00000000 --- a/backend/model/log.go +++ /dev/null @@ -1,167 +0,0 @@ -package model - -import ( - "crawlab/database" - "crawlab/utils" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "os" - "runtime/debug" - "time" -) - -type LogItem struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - Message string `json:"msg" bson:"msg"` - TaskId string `json:"task_id" bson:"task_id"` - Seq int64 `json:"seq" bson:"seq"` - Ts time.Time `json:"ts" bson:"ts"` - ExpireTs time.Time `json:"expire_ts" bson:"expire_ts"` -} - -type ErrorLogItem struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - TaskId string `json:"task_id" bson:"task_id"` - Message string `json:"msg" bson:"msg"` - LogId bson.ObjectId `json:"log_id" bson:"log_id"` - Seq int64 `json:"seq" bson:"seq"` - Ts time.Time `json:"ts" bson:"ts"` - ExpireTs time.Time `json:"expire_ts" bson:"expire_ts"` -} - -// 获取本地日志 -func GetLocalLog(logPath string) (fileBytes []byte, err error) { - - f, err := os.Open(logPath) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return nil, err - } - fi, err := f.Stat() - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return nil, err - } - defer utils.Close(f) - - const bufLen = 2 * 1024 * 1024 - logBuf := make([]byte, bufLen) - - off := int64(0) - if fi.Size() > int64(len(logBuf)) { - off = fi.Size() - int64(len(logBuf)) - } - n, err := f.ReadAt(logBuf, off) - - //到文件结尾会有EOF标识 - if err != nil && err.Error() != "EOF" { - log.Error(err.Error()) - debug.PrintStack() - return nil, err - } - logBuf = logBuf[:n] - return logBuf, nil -} - -func AddLogItem(l LogItem) error { - s, c := database.GetCol("logs") - defer s.Close() - if err := c.Insert(l); err != nil { - log.Errorf("insert log error: " + err.Error()) - debug.PrintStack() - return err - } - return nil -} - -func AddLogItems(ls []LogItem) error { - if len(ls) == 0 { - return nil - } - s, c := database.GetCol("logs") - defer s.Close() - var docs []interface{} - for _, l := range ls { - docs = append(docs, l) - } - if err := c.Insert(docs...); err != nil { - log.Errorf("insert log error: " + err.Error()) - debug.PrintStack() - return err - } - return nil -} - -func AddErrorLogItem(e ErrorLogItem) error { - s, c := database.GetCol("error_logs") - defer s.Close() - var l LogItem - err := c.FindId(bson.M{"log_id": e.LogId}).One(&l) - if err != nil && err == mgo.ErrNotFound { - if err := c.Insert(e); err != nil { - log.Errorf("insert log error: " + err.Error()) - debug.PrintStack() - return err - } - } - return nil -} - -func GetLogItemList(query bson.M, keyword string, skip int, limit int, sortStr string) ([]LogItem, error) { - s, c := database.GetCol("logs") - defer s.Close() - - filter := query - - var logItems []LogItem - if keyword == "" { - filter["seq"] = bson.M{ - "$gte": skip, - "$lt": skip + limit, - } - if err := c.Find(filter).Sort(sortStr).All(&logItems); err != nil { - debug.PrintStack() - return logItems, err - } - } else { - filter["msg"] = bson.M{ - "$regex": bson.RegEx{ - Pattern: keyword, - Options: "i", - }, - } - if err := c.Find(filter).Sort(sortStr).Skip(skip).Limit(limit).All(&logItems); err != nil { - debug.PrintStack() - return logItems, err - } - } - - return logItems, nil -} - -func GetLogItemTotal(query bson.M, keyword string) (int, error) { - s, c := database.GetCol("logs") - defer s.Close() - - filter := query - - if keyword != "" { - filter["msg"] = bson.M{ - "$regex": bson.RegEx{ - Pattern: keyword, - Options: "i", - }, - } - } - - total, err := c.Find(filter).Count() - if err != nil { - debug.PrintStack() - return total, err - } - - return total, nil -} diff --git a/backend/model/market/repo.go b/backend/model/market/repo.go deleted file mode 100644 index 33697879..00000000 --- a/backend/model/market/repo.go +++ /dev/null @@ -1,4 +0,0 @@ -package market - -type Repo struct { -} diff --git a/backend/model/node.go b/backend/model/node.go deleted file mode 100644 index 2b7f193a..00000000 --- a/backend/model/node.go +++ /dev/null @@ -1,232 +0,0 @@ -package model - -import ( - "crawlab/constants" - "crawlab/database" - "errors" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "github.com/spf13/viper" - "runtime/debug" - "time" -) - -type Node struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - Name string `json:"name" bson:"name"` - Status string `json:"status" bson:"status"` - Ip string `json:"ip" bson:"ip"` - Port string `json:"port" bson:"port"` - Mac string `json:"mac" bson:"mac"` - Hostname string `json:"hostname" bson:"hostname"` - Description string `json:"description" bson:"description"` - // 用于唯一标识节点,可能是mac地址,可能是ip地址 - Key string `json:"key" bson:"key"` - - // 前端展示 - IsMaster bool `json:"is_master" bson:"is_master"` - - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTsUnix int64 `json:"update_ts_unix" bson:"update_ts_unix"` -} - -const ( - Yes = "Y" -) - -// 当前节点是否为主节点 -func IsMaster() bool { - return viper.GetString("server.master") == Yes -} - -func (n *Node) Save() error { - s, c := database.GetCol("nodes") - defer s.Close() - n.UpdateTs = time.Now() - if err := c.UpdateId(n.Id, n); err != nil { - return err - } - return nil -} - -func (n *Node) Add() error { - s, c := database.GetCol("nodes") - defer s.Close() - n.Id = bson.NewObjectId() - n.UpdateTs = time.Now() - n.UpdateTsUnix = time.Now().Unix() - n.CreateTs = time.Now() - if err := c.Insert(&n); err != nil { - debug.PrintStack() - return err - } - return nil -} - -func (n *Node) Delete() error { - s, c := database.GetCol("nodes") - defer s.Close() - if err := c.RemoveId(n.Id); err != nil { - debug.PrintStack() - return err - } - return nil -} - -func (n *Node) GetTasks() ([]Task, error) { - tasks, err := GetTaskList(bson.M{"node_id": n.Id}, 0, 10, "-create_ts") - //tasks, err := GetTaskList(nil, 0, 10, "-create_ts") - if err != nil { - debug.PrintStack() - return []Task{}, err - } - - return tasks, nil -} - -// 节点列表 -func GetNodeList(filter interface{}) ([]Node, error) { - s, c := database.GetCol("nodes") - defer s.Close() - - var results []Node - if err := c.Find(filter).All(&results); err != nil { - log.Error("get node list error: " + err.Error()) - debug.PrintStack() - return results, err - } - return results, nil -} - -// 节点信息 -func GetNode(id bson.ObjectId) (Node, error) { - var node Node - - if id.Hex() == "" { - log.Infof("id is empty") - debug.PrintStack() - return node, errors.New("id is empty") - } - - s, c := database.GetCol("nodes") - defer s.Close() - - if err := c.FindId(id).One(&node); err != nil { - //log.Errorf("get node error: %s, id: %s", err.Error(), id.Hex()) - //debug.PrintStack() - return node, err - } - return node, nil -} - -// 节点信息 -func GetNodeByKey(key string) (Node, error) { - s, c := database.GetCol("nodes") - defer s.Close() - - var node Node - if err := c.Find(bson.M{"key": key}).One(&node); err != nil { - if err != mgo.ErrNotFound { - log.Errorf(err.Error()) - debug.PrintStack() - } - return node, err - } - return node, nil -} - -// 更新节点 -func UpdateNode(id bson.ObjectId, item Node) error { - s, c := database.GetCol("nodes") - defer s.Close() - - var node Node - if err := c.FindId(id).One(&node); err != nil { - return err - } - - if err := item.Save(); err != nil { - return err - } - return nil -} - -// 任务列表 -func GetNodeTaskList(id bson.ObjectId) ([]Task, error) { - node, err := GetNode(id) - if err != nil { - return []Task{}, err - } - tasks, err := node.GetTasks() - if err != nil { - return []Task{}, err - } - return tasks, nil -} - -// 节点数 -func GetNodeCount(query interface{}) (int, error) { - s, c := database.GetCol("nodes") - defer s.Close() - - count, err := c.Find(query).Count() - if err != nil { - return 0, err - } - - return count, nil -} - -// 根据redis的key值,重置node节点为offline -func ResetNodeStatusToOffline(list []string) { - nodes, _ := GetNodeList(nil) - for _, node := range nodes { - hasNode := false - for _, key := range list { - if key == node.Key { - hasNode = true - break - } - } - if !hasNode || node.Status == "" { - node.Status = constants.StatusOffline - if err := node.Save(); err != nil { - log.Errorf(err.Error()) - return - } - continue - } - } -} - -func UpdateMasterNodeInfo(key string, ip string, mac string, hostname string) error { - s, c := database.GetCol("nodes") - defer s.Close() - c.UpdateAll(bson.M{ - "is_master": true, - }, bson.M{ - "is_master": false, - }) - _, err := c.Upsert(bson.M{ - "key": key, - }, bson.M{ - "$set": bson.M{ - "ip": ip, - "port": "8000", - "mac": mac, - "hostname": hostname, - "is_master": true, - "update_ts": time.Now(), - "update_ts_unix": time.Now().Unix(), - }, - "$setOnInsert": bson.M{ - "key": key, - "name": key, - "create_ts": time.Now(), - "_id": bson.NewObjectId(), - }, - }) - return err -} diff --git a/backend/model/node_test.go b/backend/model/node_test.go deleted file mode 100644 index ba3f4aaa..00000000 --- a/backend/model/node_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package model - -import ( - "crawlab/config" - "crawlab/constants" - "crawlab/database" - "github.com/apex/log" - . "github.com/smartystreets/goconvey/convey" - "runtime/debug" - "testing" -) - -func TestAddNode(t *testing.T) { - Convey("Test AddNode", t, func() { - if err := config.InitConfig("../conf/config.yml"); err != nil { - log.Error("init config error:" + err.Error()) - panic(err) - } - log.Info("初始化配置成功") - - // 初始化Mongodb数据库 - if err := database.InitMongo(); err != nil { - log.Error("init mongodb error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("初始化Mongodb数据库成功") - - // 初始化Redis数据库 - if err := database.InitRedis(); err != nil { - log.Error("init redis error:" + err.Error()) - debug.PrintStack() - panic(err) - } - - var node = Node{ - Key: "c4:b3:01:bd:b5:e7", - Name: "10.27.238.101", - Ip: "10.27.238.101", - Port: "8000", - Mac: "c4:b3:01:bd:b5:e7", - Status: constants.StatusOnline, - IsMaster: true, - } - if err := node.Add(); err != nil { - log.Error("add node error:" + err.Error()) - panic(err) - } - }) -} diff --git a/backend/model/project.go b/backend/model/project.go deleted file mode 100644 index 2889d6aa..00000000 --- a/backend/model/project.go +++ /dev/null @@ -1,167 +0,0 @@ -package model - -import ( - "crawlab/constants" - "crawlab/database" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "runtime/debug" - "time" -) - -type Project struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - Name string `json:"name" bson:"name"` - Description string `json:"description" bson:"description"` - Tags []string `json:"tags" bson:"tags"` - - // 前端展示 - Spiders []Spider `json:"spiders" bson:"spiders"` - Username string `json:"username" bson:"username"` - - UserId bson.ObjectId `json:"user_id" bson:"user_id"` - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` -} - -func (p *Project) Save() error { - s, c := database.GetCol("projects") - defer s.Close() - - p.UpdateTs = time.Now() - - if err := c.UpdateId(p.Id, p); err != nil { - debug.PrintStack() - return err - } - return nil -} - -func (p *Project) Add() error { - s, c := database.GetCol("projects") - defer s.Close() - - p.Id = bson.NewObjectId() - p.UpdateTs = time.Now() - p.CreateTs = time.Now() - if err := c.Insert(p); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func (p *Project) GetSpiders() ([]Spider, error) { - s, c := database.GetCol("spiders") - defer s.Close() - - var query interface{} - if p.Id.Hex() == constants.ObjectIdNull { - query = bson.M{ - "$or": []bson.M{ - {"project_id": p.Id}, - {"project_id": bson.M{"$exists": false}}, - }, - } - } else { - query = bson.M{"project_id": p.Id} - } - - var spiders []Spider - if err := c.Find(query).All(&spiders); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return spiders, err - } - - return spiders, nil -} - -func GetProject(id bson.ObjectId) (Project, error) { - s, c := database.GetCol("projects") - defer s.Close() - var p Project - if err := c.Find(bson.M{"_id": id}).One(&p); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return p, err - } - return p, nil -} - -func GetProjectList(filter interface{}, sortKey string) ([]Project, error) { - s, c := database.GetCol("projects") - defer s.Close() - - var projects []Project - if err := c.Find(filter).Sort(sortKey).All(&projects); err != nil { - debug.PrintStack() - return projects, err - } - - for i, p := range projects { - // 获取用户名称 - user, _ := GetUser(p.UserId) - projects[i].Username = user.Username - } - return projects, nil -} - -func GetProjectListTotal(filter interface{}) (int, error) { - s, c := database.GetCol("projects") - defer s.Close() - - var result int - result, err := c.Find(filter).Count() - if err != nil { - return result, err - } - return result, nil -} - -func UpdateProject(id bson.ObjectId, item Project) error { - s, c := database.GetCol("projects") - defer s.Close() - - var result Project - if err := c.FindId(id).One(&result); err != nil { - debug.PrintStack() - return err - } - - if err := item.Save(); err != nil { - return err - } - return nil -} - -func RemoveProject(id bson.ObjectId) error { - s, c := database.GetCol("projects") - defer s.Close() - - var result User - if err := c.FindId(id).One(&result); err != nil { - return err - } - - if err := c.RemoveId(id); err != nil { - return err - } - - return nil -} - -func GetProjectCount(filter interface{}) (int, error) { - s, c := database.GetCol("projects") - defer s.Close() - - count, err := c.Find(filter).Count() - if err != nil { - return 0, err - } - - return count, nil -} - diff --git a/backend/model/schedule.go b/backend/model/schedule.go deleted file mode 100644 index 5d0da286..00000000 --- a/backend/model/schedule.go +++ /dev/null @@ -1,177 +0,0 @@ -package model - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/lib/cron" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "runtime/debug" - "time" -) - -type Schedule struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - Name string `json:"name" bson:"name"` - Description string `json:"description" bson:"description"` - SpiderId bson.ObjectId `json:"spider_id" bson:"spider_id"` - Cron string `json:"cron" bson:"cron"` - EntryId cron.EntryID `json:"entry_id" bson:"entry_id"` - Param string `json:"param" bson:"param"` - RunType string `json:"run_type" bson:"run_type"` - NodeIds []bson.ObjectId `json:"node_ids" bson:"node_ids"` - Status string `json:"status" bson:"status"` - Enabled bool `json:"enabled" bson:"enabled"` - UserId bson.ObjectId `json:"user_id" bson:"user_id"` - ScrapySpider string `json:"scrapy_spider" bson:"scrapy_spider"` - ScrapyLogLevel string `json:"scrapy_log_level" bson:"scrapy_log_level"` - - // 前端展示 - SpiderName string `json:"spider_name" bson:"spider_name"` - Username string `json:"user_name" bson:"user_name"` - Nodes []Node `json:"nodes" bson:"nodes"` - Message string `json:"message" bson:"message"` - - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` -} - -func (sch *Schedule) Save() error { - s, c := database.GetCol("schedules") - defer s.Close() - sch.UpdateTs = time.Now() - if err := c.UpdateId(sch.Id, sch); err != nil { - return err - } - return nil -} - -func (sch *Schedule) Delete() error { - s, c := database.GetCol("schedules") - defer s.Close() - return c.RemoveId(sch.Id) -} - -func GetScheduleList(filter interface{}) ([]Schedule, error) { - s, c := database.GetCol("schedules") - defer s.Close() - - var schedules []Schedule - if err := c.Find(filter).All(&schedules); err != nil { - return schedules, err - } - - var schs []Schedule - for _, schedule := range schedules { - // 获取节点名称 - schedule.Nodes = []Node{} - if schedule.RunType == constants.RunTypeSelectedNodes { - for _, nodeId := range schedule.NodeIds { - // 选择单一节点 - node, err := GetNode(nodeId) - if err != nil { - continue - } - schedule.Nodes = append(schedule.Nodes, node) - } - } - - // 获取爬虫名称 - spider, err := GetSpider(schedule.SpiderId) - if err != nil { - log.Errorf("get spider by id: %s, error: %s", schedule.SpiderId.Hex(), err.Error()) - schedule.Status = constants.ScheduleStatusError - if err == mgo.ErrNotFound { - schedule.Message = constants.ScheduleStatusErrorNotFoundSpider - } else { - schedule.Message = err.Error() - } - } else { - schedule.SpiderName = spider.Name - } - - // 获取用户名称 - user, _ := GetUser(schedule.UserId) - schedule.Username = user.Username - - schs = append(schs, schedule) - } - return schs, nil -} - -func GetSchedule(id bson.ObjectId) (Schedule, error) { - s, c := database.GetCol("schedules") - defer s.Close() - - var schedule Schedule - if err := c.FindId(id).One(&schedule); err != nil { - return schedule, err - } - - // 获取用户名称 - user, _ := GetUser(schedule.UserId) - schedule.Username = user.Username - - return schedule, nil -} - -func UpdateSchedule(id bson.ObjectId, item Schedule) error { - s, c := database.GetCol("schedules") - defer s.Close() - - var result Schedule - if err := c.FindId(id).One(&result); err != nil { - return err - } - - item.UpdateTs = time.Now() - if err := item.Save(); err != nil { - return err - } - return nil -} - -func AddSchedule(item Schedule) error { - s, c := database.GetCol("schedules") - defer s.Close() - - item.Id = bson.NewObjectId() - item.CreateTs = time.Now() - item.UpdateTs = time.Now() - - if err := c.Insert(&item); err != nil { - debug.PrintStack() - log.Errorf(err.Error()) - return err - } - return nil -} - -func RemoveSchedule(id bson.ObjectId) error { - s, c := database.GetCol("schedules") - defer s.Close() - - var result Schedule - if err := c.FindId(id).One(&result); err != nil { - return err - } - - if err := c.RemoveId(id); err != nil { - return err - } - - return nil -} - -func GetScheduleCount(filter interface{}) (int, error) { - s, c := database.GetCol("schedules") - defer s.Close() - - count, err := c.Find(filter).Count() - if err != nil { - return 0, err - } - - return count, nil -} diff --git a/backend/model/setting.go b/backend/model/setting.go deleted file mode 100644 index 3b546f68..00000000 --- a/backend/model/setting.go +++ /dev/null @@ -1,45 +0,0 @@ -package model - -import ( - "crawlab/database" - "github.com/globalsign/mgo/bson" - "time" -) - -type Setting struct { - Keyword string - Document bson.Raw -} - -func GetRawSetting(keyword string, pointer interface{}) error { - s, col := database.GetCol("settings") - defer s.Close() - var setting Setting - err := col.Find(bson.M{"keyword": keyword}).One(&setting) - if err != nil { - return err - } - return setting.Document.Unmarshal(pointer) -} - -type DocumentMeta struct { - DocumentVersion int - DocStructVersion int - UpdateTime time.Time - CreateTime time.Time - DeleteTime time.Time -} - -//demo -type SecuritySetting struct { - EnableRegister bool - EnableInvitation bool - DocumentMeta `bson:"inline" json:"inline"` -} - -func GetSecuritySetting() (SecuritySetting, error) { - var app SecuritySetting - err := GetRawSetting("security", &app) - return app, err - -} diff --git a/backend/model/spider.go b/backend/model/spider.go deleted file mode 100644 index d6ff72d4..00000000 --- a/backend/model/spider.go +++ /dev/null @@ -1,414 +0,0 @@ -package model - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/entity" - "crawlab/utils" - "errors" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "gopkg.in/yaml.v2" - "io/ioutil" - "path/filepath" - "runtime/debug" - "time" -) - -type Env struct { - Name string `json:"name" bson:"name"` - Value string `json:"value" bson:"value"` -} - -type Spider struct { - Id bson.ObjectId `json:"_id" bson:"_id"` // 爬虫ID - Name string `json:"name" bson:"name"` // 爬虫名称(唯一) - DisplayName string `json:"display_name" bson:"display_name"` // 爬虫显示名称 - Type string `json:"type" bson:"type"` // 爬虫类别 - FileId bson.ObjectId `json:"file_id" bson:"file_id"` // GridFS文件ID - Col string `json:"col" bson:"col"` // 结果储存位置 - Site string `json:"site" bson:"site"` // 爬虫网站 - Envs []Env `json:"envs" bson:"envs"` // 环境变量 - Remark string `json:"remark" bson:"remark"` // 备注 - Src string `json:"src" bson:"src"` // 源码位置 - ProjectId bson.ObjectId `json:"project_id" bson:"project_id"` // 项目ID - IsPublic bool `json:"is_public" bson:"is_public"` // 是否公开 - - // 自定义爬虫 - Cmd string `json:"cmd" bson:"cmd"` // 执行命令 - - // Scrapy 爬虫(属于自定义爬虫) - IsScrapy bool `json:"is_scrapy" bson:"is_scrapy"` // 是否为 Scrapy 爬虫 - SpiderNames []string `json:"spider_names" bson:"spider_names"` // 爬虫名称列表 - - // 可配置爬虫 - Template string `json:"template" bson:"template"` // Spiderfile模版 - - // Git 设置 - IsGit bool `json:"is_git" bson:"is_git"` // 是否为 Git - GitUrl string `json:"git_url" bson:"git_url"` // Git URL - GitBranch string `json:"git_branch" bson:"git_branch"` // Git 分支 - GitHasCredential bool `json:"git_has_credential" bson:"git_has_credential"` // Git 是否加密 - GitUsername string `json:"git_username" bson:"git_username"` // Git 用户名 - GitPassword string `json:"git_password" bson:"git_password"` // Git 密码 - GitAutoSync bool `json:"git_auto_sync" bson:"git_auto_sync"` // Git 是否自动同步 - GitSyncFrequency string `json:"git_sync_frequency" bson:"git_sync_frequency"` // Git 同步频率 - GitSyncError string `json:"git_sync_error" bson:"git_sync_error"` // Git 同步错误 - - // 长任务 - IsLongTask bool `json:"is_long_task" bson:"is_long_task"` // 是否为长任务 - - // 去重 - IsDedup bool `json:"is_dedup" bson:"is_dedup"` // 是否去重 - DedupField string `json:"dedup_field" bson:"dedup_field"` // 去重字段 - DedupMethod string `json:"dedup_method" bson:"dedup_method"` // 去重方式 - - // Web Hook - IsWebHook bool `json:"is_web_hook" bson:"is_web_hook"` // 是否开启 Web Hook - WebHookUrl string `json:"web_hook_url" bson:"web_hook_url"` // Web Hook URL - - // 前端展示 - LastRunTs time.Time `json:"last_run_ts"` // 最后一次执行时间 - LastStatus string `json:"last_status"` // 最后执行状态 - Config entity.ConfigSpiderData `json:"config"` // 可配置爬虫配置 - LatestTasks []Task `json:"latest_tasks"` // 最近任务列表 - Username string `json:"username"` // 用户名称 - ProjectName string `json:"project_name"` // 项目名称 - - // 时间 - UserId bson.ObjectId `json:"user_id" bson:"user_id"` - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` -} - -// 更新爬虫 -func (spider *Spider) Save() error { - s, c := database.GetCol("spiders") - defer s.Close() - - spider.UpdateTs = time.Now() - - // 兼容没有项目ID的爬虫 - if spider.ProjectId.Hex() == "" { - spider.ProjectId = bson.ObjectIdHex(constants.ObjectIdNull) - } - - if err := c.UpdateId(spider.Id, spider); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - return nil -} - -// 新增爬虫 -func (spider *Spider) Add() error { - s, c := database.GetCol("spiders") - defer s.Close() - - spider.Id = bson.NewObjectId() - spider.CreateTs = time.Now() - spider.UpdateTs = time.Now() - - if !spider.ProjectId.Valid() { - spider.ProjectId = bson.ObjectIdHex(constants.ObjectIdNull) - } - - if err := c.Insert(&spider); err != nil { - return err - } - return nil -} - -// 获取爬虫的任务 -func (spider *Spider) GetTasks() ([]Task, error) { - tasks, err := GetTaskList(bson.M{"spider_id": spider.Id}, 0, 10, "-create_ts") - if err != nil { - return tasks, err - } - return tasks, nil -} - -// 爬虫最新的任务 -func (spider *Spider) GetLastTask() (Task, error) { - tasks, err := GetTaskList(bson.M{"spider_id": spider.Id}, 0, 1, "-create_ts") - if err != nil { - return Task{}, err - } - if tasks == nil { - return Task{}, nil - } - return tasks[0], nil -} - -// 爬虫正在运行的任务 -func (spider *Spider) GetLatestTasks(latestN int) (tasks []Task, err error) { - tasks, err = GetTaskList(bson.M{"spider_id": spider.Id}, 0, latestN, "-create_ts") - if err != nil { - return tasks, err - } - if tasks == nil { - return tasks, err - } - return tasks, nil -} - -// 删除爬虫 -func (spider *Spider) Delete() error { - s, c := database.GetCol("spiders") - defer s.Close() - return c.RemoveId(spider.Id) -} - -// 获取爬虫列表 -func GetSpiderList(filter interface{}, skip int, limit int, sortStr string) ([]Spider, int, error) { - s, c := database.GetCol("spiders") - defer s.Close() - - // 获取爬虫列表 - var spiders []Spider - if err := c.Find(filter).Skip(skip).Limit(limit).Sort(sortStr).All(&spiders); err != nil { - debug.PrintStack() - return spiders, 0, err - } - - if spiders == nil { - spiders = []Spider{} - } - - // 遍历爬虫列表 - for i, spider := range spiders { - // 获取最后一次任务 - task, err := spider.GetLastTask() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - } - - // 获取正在运行的爬虫 - latestTasks, err := spider.GetLatestTasks(50) // TODO: latestN 暂时写死,后面加入数据库 - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - } - - // 获取用户 - var user User - if spider.UserId.Valid() && spider.UserId.Hex() != constants.ObjectIdNull { - user, err = GetUser(spider.UserId) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - } - } - - // 获取项目 - var project Project - if spider.ProjectId.Valid() && spider.ProjectId.Hex() != constants.ObjectIdNull { - project, err = GetProject(spider.ProjectId) - if err != nil { - if err != mgo.ErrNotFound { - log.Errorf(err.Error()) - debug.PrintStack() - } - } - } - - // 赋值 - spiders[i].LastRunTs = task.CreateTs - spiders[i].LastStatus = task.Status - spiders[i].LatestTasks = latestTasks - spiders[i].Username = user.Username - spiders[i].ProjectName = project.Name - } - - count, _ := c.Find(filter).Count() - - return spiders, count, nil -} - -// 获取所有爬虫列表 -func GetSpiderAllList(filter interface{}) (spiders []Spider, err error) { - spiders, _, err = GetSpiderList(filter, 0, constants.Infinite, "_id") - if err != nil { - return spiders, err - } - return spiders, nil -} - -// 获取爬虫(根据FileId) -func GetSpiderByFileId(fileId bson.ObjectId) *Spider { - s, c := database.GetCol("spiders") - defer s.Close() - - var result *Spider - if err := c.Find(bson.M{"file_id": fileId}).One(&result); err != nil { - log.Errorf("get spider error: %s, file_id: %s", err.Error(), fileId.Hex()) - debug.PrintStack() - return nil - } - return result -} - -// 获取爬虫(根据名称) -func GetSpiderByName(name string) Spider { - s, c := database.GetCol("spiders") - defer s.Close() - - var spider Spider - if err := c.Find(bson.M{"name": name}).One(&spider); err != nil && err != mgo.ErrNotFound { - log.Errorf("get spider error: %s, spider_name: %s", err.Error(), name) - //debug.PrintStack() - return spider - } - - // 获取用户 - var user User - if spider.UserId.Valid() { - user, _ = GetUser(spider.UserId) - } - spider.Username = user.Username - - return spider -} - -// 获取爬虫(根据ID) -func GetSpider(id bson.ObjectId) (Spider, error) { - s, c := database.GetCol("spiders") - defer s.Close() - - // 获取爬虫 - var spider Spider - if err := c.FindId(id).One(&spider); err != nil { - if err != mgo.ErrNotFound { - log.Errorf("get spider error: %s, id: %id", err.Error(), id.Hex()) - debug.PrintStack() - } - return spider, err - } - - // 如果为可配置爬虫,获取爬虫配置 - if spider.Type == constants.Configurable && utils.Exists(filepath.Join(spider.Src, "Spiderfile")) { - config, err := GetConfigSpiderData(spider) - if err != nil { - return spider, err - } - spider.Config = config - } - - // 获取用户名称 - var user User - if spider.UserId.Valid() { - user, _ = GetUser(spider.UserId) - } - spider.Username = user.Username - - return spider, nil -} - -// 更新爬虫 -func UpdateSpider(id bson.ObjectId, item Spider) error { - s, c := database.GetCol("spiders") - defer s.Close() - - var result Spider - if err := c.FindId(id).One(&result); err != nil { - debug.PrintStack() - return err - } - - if err := item.Save(); err != nil { - return err - } - return nil -} - -// 删除爬虫 -func RemoveSpider(id bson.ObjectId) error { - s, c := database.GetCol("spiders") - defer s.Close() - - var result Spider - if err := c.FindId(id).One(&result); err != nil { - log.Errorf("find spider error: %s, id:%s", err.Error(), id.Hex()) - debug.PrintStack() - return err - } - - if err := c.RemoveId(id); err != nil { - log.Errorf("remove spider error: %s, id:%s", err.Error(), id.Hex()) - debug.PrintStack() - return err - } - - // gf上的文件 - s, gf := database.GetGridFs("files") - defer s.Close() - if result.FileId.Hex() != constants.ObjectIdNull { - if err := gf.RemoveId(result.FileId); err != nil { - log.Error("remove file error, id:" + result.FileId.Hex()) - debug.PrintStack() - } - } - - return nil -} - -// 删除所有爬虫 -func RemoveAllSpider() error { - s, c := database.GetCol("spiders") - defer s.Close() - - var spiders []Spider - err := c.Find(nil).All(&spiders) - if err != nil { - log.Error("get all spiders error:" + err.Error()) - return err - } - for _, spider := range spiders { - if err := RemoveSpider(spider.Id); err != nil { - log.Error("remove spider error:" + err.Error()) - } - } - return nil -} - -// 获取爬虫总数 -func GetSpiderCount(filter interface{}) (int, error) { - s, c := database.GetCol("spiders") - defer s.Close() - - count, err := c.Find(filter).Count() - if err != nil { - return 0, err - } - return count, nil -} - -// 获取爬虫定时任务 -func GetConfigSpiderData(spider Spider) (entity.ConfigSpiderData, error) { - // 构造配置数据 - configData := entity.ConfigSpiderData{} - - // 校验爬虫类别 - if spider.Type != constants.Configurable { - return configData, errors.New("not a configurable spider") - } - - // Spiderfile 目录 - sfPath := filepath.Join(spider.Src, "Spiderfile") - - // 读取YAML文件 - yamlFile, err := ioutil.ReadFile(sfPath) - if err != nil { - return configData, err - } - - // 反序列化 - if err := yaml.Unmarshal(yamlFile, &configData); err != nil { - return configData, err - } - - return configData, nil -} diff --git a/backend/model/system.go b/backend/model/system.go deleted file mode 100644 index 5c2f5997..00000000 --- a/backend/model/system.go +++ /dev/null @@ -1,98 +0,0 @@ -package model - -import ( - "crawlab/entity" - "github.com/apex/log" - "io/ioutil" - "os" - "path/filepath" - "runtime" - "runtime/debug" - "strings" -) - -var executableNameMap = map[string]string{ - // python - "python": "Python", - "python2": "Python 2", - "python2.7": "Python 2.7", - "python3": "Python 3", - "python3.5": "Python 3.5", - "python3.6": "Python 3.6", - "python3.7": "Python 3.7", - "python3.8": "Python 3.8", - // java - "java": "Java", - // go - "go": "Go", - // node - "node": "NodeJS", - // php - "php": "PHP", - // windows command - "cmd": "Windows Command Prompt", - // linux shell - "sh": "Shell", - "bash": "bash", -} - -func GetLocalSystemInfo() (sysInfo entity.SystemInfo, err error) { - executables, err := GetExecutables() - if err != nil { - return sysInfo, err - } - hostname, err := os.Hostname() - if err != nil { - debug.PrintStack() - return sysInfo, err - } - - return entity.SystemInfo{ - ARCH: runtime.GOARCH, - OS: runtime.GOOS, - NumCpu: runtime.GOMAXPROCS(0), - Hostname: hostname, - Executables: executables, - }, nil -} - -func GetSystemEnv(key string) string { - return os.Getenv(key) -} - -func GetPathValues() (paths []string) { - pathEnv := GetSystemEnv("PATH") - return strings.Split(pathEnv, ":") -} - -func GetExecutables() (executables []entity.Executable, err error) { - pathValues := GetPathValues() - - cache := map[string]string{} - - for _, path := range pathValues { - fileList, err := ioutil.ReadDir(path) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - - for _, file := range fileList { - displayName := executableNameMap[file.Name()] - filePath := filepath.Join(path, file.Name()) - - if cache[filePath] == "" { - if displayName != "" { - executables = append(executables, entity.Executable{ - Path: filePath, - FileName: file.Name(), - DisplayName: displayName, - }) - } - cache[filePath] = filePath - } - } - } - return executables, nil -} diff --git a/backend/model/task.go b/backend/model/task.go deleted file mode 100644 index 789bfafb..00000000 --- a/backend/model/task.go +++ /dev/null @@ -1,534 +0,0 @@ -package model - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/utils" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "runtime/debug" - "time" -) - -type Task struct { - Id string `json:"_id" bson:"_id"` - SpiderId bson.ObjectId `json:"spider_id" bson:"spider_id"` - StartTs time.Time `json:"start_ts" bson:"start_ts"` - FinishTs time.Time `json:"finish_ts" bson:"finish_ts"` - Status string `json:"status" bson:"status"` - NodeId bson.ObjectId `json:"node_id" bson:"node_id"` - LogPath string `json:"log_path" bson:"log_path"` - Cmd string `json:"cmd" bson:"cmd"` - Param string `json:"param" bson:"param"` - Error string `json:"error" bson:"error"` - ResultCount int `json:"result_count" bson:"result_count"` - ErrorLogCount int `json:"error_log_count" bson:"error_log_count"` - WaitDuration float64 `json:"wait_duration" bson:"wait_duration"` - RuntimeDuration float64 `json:"runtime_duration" bson:"runtime_duration"` - TotalDuration float64 `json:"total_duration" bson:"total_duration"` - Pid int `json:"pid" bson:"pid"` - RunType string `json:"run_type" bson:"run_type"` - ScheduleId bson.ObjectId `json:"schedule_id" bson:"schedule_id"` - Type string `json:"type" bson:"type"` - - // 前端数据 - SpiderName string `json:"spider_name"` - NodeName string `json:"node_name"` - Username string `json:"username"` - NodeIds []string `json:"node_ids"` - - UserId bson.ObjectId `json:"user_id" bson:"user_id"` - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` -} - -type TaskDailyItem struct { - Date string `json:"date" bson:"_id"` - TaskCount int `json:"task_count" bson:"task_count"` - AvgRuntimeDuration float64 `json:"avg_runtime_duration" bson:"avg_runtime_duration"` -} - -func (t *Task) GetSpider() (Spider, error) { - spider, err := GetSpider(t.SpiderId) - if err != nil { - return spider, err - } - return spider, nil -} - -func (t *Task) GetNode() (Node, error) { - node, err := GetNode(t.NodeId) - if err != nil { - return node, err - } - return node, nil -} - -func (t *Task) Save() error { - s, c := database.GetCol("tasks") - defer s.Close() - t.UpdateTs = time.Now() - if err := c.UpdateId(t.Id, t); err != nil { - log.Errorf("update task error: %s", err.Error()) - debug.PrintStack() - return err - } - return nil -} - -func (t *Task) Delete() error { - s, c := database.GetCol("tasks") - defer s.Close() - if err := c.RemoveId(t.Id); err != nil { - return err - } - return nil -} - -func (t *Task) GetResults(pageNum int, pageSize int) (results []interface{}, total int, err error) { - spider, err := t.GetSpider() - if err != nil { - log.Errorf(err.Error()) - return - } - - col := utils.GetSpiderCol(spider.Col, spider.Name) - - s, c := database.GetCol(col) - defer s.Close() - - query := bson.M{ - "task_id": t.Id, - } - if err = c.Find(query).Skip((pageNum - 1) * pageSize).Limit(pageSize).All(&results); err != nil { - return - } - - if total, err = c.Find(query).Count(); err != nil { - return - } - - return -} - -func (t *Task) GetLogItems(keyword string, page int, pageSize int) (logItems []LogItem, logTotal int, err error) { - query := bson.M{ - "task_id": t.Id, - } - - logTotal, err = GetLogItemTotal(query, keyword) - if err != nil { - return logItems, logTotal, err - } - - logItems, err = GetLogItemList(query, keyword, (page-1)*pageSize, pageSize, "+_id") - if err != nil { - return logItems, logTotal, err - } - - return logItems, logTotal, nil -} - -func (t *Task) GetErrorLogItems(n int) (errLogItems []ErrorLogItem, err error) { - s, c := database.GetCol("error_logs") - defer s.Close() - - query := bson.M{ - "task_id": t.Id, - } - - if err := c.Find(query).Limit(n).All(&errLogItems); err != nil { - log.Errorf("find error logs error: " + err.Error()) - debug.PrintStack() - return errLogItems, err - } - - return errLogItems, nil -} - -func GetTaskList(filter interface{}, skip int, limit int, sortKey string) ([]Task, error) { - s, c := database.GetCol("tasks") - defer s.Close() - - var tasks []Task - if err := c.Find(filter).Skip(skip).Limit(limit).Sort(sortKey).All(&tasks); err != nil { - debug.PrintStack() - return tasks, err - } - - for i, task := range tasks { - // 获取爬虫名称 - if spider, err := task.GetSpider(); err == nil { - tasks[i].SpiderName = spider.DisplayName - } - - // 获取节点名称 - if node, err := task.GetNode(); err == nil { - tasks[i].NodeName = node.Name - } - - // 获取用户名称 - user, _ := GetUser(task.UserId) - task.Username = user.Username - } - return tasks, nil -} - -func GetTaskListTotal(filter interface{}) (int, error) { - s, c := database.GetCol("tasks") - defer s.Close() - - var result int - result, err := c.Find(filter).Count() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return result, err - } - return result, nil -} - -func GetTask(id string) (Task, error) { - s, c := database.GetCol("tasks") - defer s.Close() - - var task Task - if err := c.FindId(id).One(&task); err != nil { - log.Infof("get task error: %s, id: %s", err.Error(), id) - debug.PrintStack() - return task, err - } - - // 获取用户名称 - user, _ := GetUser(task.UserId) - task.Username = user.Username - - return task, nil -} - -func AddTask(item Task) error { - s, c := database.GetCol("tasks") - defer s.Close() - - item.CreateTs = time.Now() - item.UpdateTs = time.Now() - - if err := c.Insert(&item); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - return nil -} - -func RemoveTask(id string) error { - s, c := database.GetCol("tasks") - defer s.Close() - - var result Task - if err := c.FindId(id).One(&result); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - if err := c.RemoveId(id); err != nil { - return err - } - - return nil -} - -func RemoveTaskByStatus(status string) error { - tasks, err := GetTaskList(bson.M{"status": status}, 0, constants.Infinite, "-create_ts") - if err != nil { - log.Error("get tasks error:" + err.Error()) - } - for _, task := range tasks { - if err := RemoveTask(task.Id); err != nil { - log.Error("remove task error:" + err.Error()) - continue - } - } - return nil -} - -// 删除task by spider_id -func RemoveTaskBySpiderId(id bson.ObjectId) error { - tasks, err := GetTaskList(bson.M{"spider_id": id}, 0, constants.Infinite, "-create_ts") - if err != nil { - log.Error("get tasks error:" + err.Error()) - } - - for _, task := range tasks { - if err := RemoveTask(task.Id); err != nil { - log.Error("remove task error:" + err.Error()) - continue - } - } - return nil -} - -// task 总数 -func GetTaskCount(query interface{}) (int, error) { - s, c := database.GetCol("tasks") - defer s.Close() - - count, err := c.Find(query).Count() - if err != nil { - return 0, err - } - - return count, nil -} - -func GetDailyTaskStats(query bson.M) ([]TaskDailyItem, error) { - s, c := database.GetCol("tasks") - defer s.Close() - - // 起始日期 - startDate := time.Now().Add(-30 * 24 * time.Hour) - endDate := time.Now() - - // query - query["create_ts"] = bson.M{ - "$gte": startDate, - "$lt": endDate, - } - - // match - op1 := bson.M{ - "$match": query, - } - - // project - op2 := bson.M{ - "$project": bson.M{ - "date": bson.M{ - "$dateToString": bson.M{ - "format": "%Y%m%d", - "date": "$create_ts", - "timezone": "Asia/Shanghai", - }, - }, - "success_count": bson.M{ - "$cond": []interface{}{ - bson.M{ - "$eq": []string{ - "$status", - constants.StatusFinished, - }, - }, - 1, - 0, - }, - }, - "runtime_duration": "$runtime_duration", - }, - } - - // group - op3 := bson.M{ - "$group": bson.M{ - "_id": "$date", - "task_count": bson.M{"$sum": 1}, - "runtime_duration": bson.M{"$sum": "$runtime_duration"}, - }, - } - - op4 := bson.M{ - "$project": bson.M{ - "task_count": "$task_count", - "date": "$date", - "avg_runtime_duration": bson.M{ - "$divide": []string{"$runtime_duration", "$task_count"}, - }, - }, - } - - // run aggregation - var items []TaskDailyItem - if err := c.Pipe([]bson.M{op1, op2, op3, op4}).All(&items); err != nil { - return items, err - } - - // 缓存每日数据 - dict := make(map[string]TaskDailyItem) - for _, item := range items { - dict[item.Date] = item - } - - // 遍历日期 - var dailyItems []TaskDailyItem - for date := startDate; endDate.Sub(date) > 0; date = date.Add(24 * time.Hour) { - dateStr := date.Format("20060102") - dailyItems = append(dailyItems, TaskDailyItem{ - Date: dateStr, - TaskCount: dict[dateStr].TaskCount, - AvgRuntimeDuration: dict[dateStr].AvgRuntimeDuration, - }) - } - - return dailyItems, nil -} - -// 更新task的结果数 -func UpdateTaskResultCount(id string) (err error) { - // 获取任务 - task, err := GetTask(id) - if err != nil { - log.Errorf(err.Error()) - return err - } - - // 获取爬虫 - spider, err := GetSpider(task.SpiderId) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // default results collection - col := utils.GetSpiderCol(spider.Col, spider.Name) - - // 获取结果数量 - s, c := database.GetCol(col) - defer s.Close() - resultCount, err := c.Find(bson.M{"task_id": task.Id}).Count() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 保存结果数量 - task.ResultCount = resultCount - if err := task.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - return nil -} - -// update error log count -func UpdateErrorLogCount(id string) (err error) { - s, c := database.GetCol("error_logs") - defer s.Close() - - query := bson.M{ - "task_id": id, - } - count, err := c.Find(query).Count() - if err != nil { - log.Errorf("update error log count error: " + err.Error()) - debug.PrintStack() - return err - } - - st, ct := database.GetCol("tasks") - defer st.Close() - - task, err := GetTask(id) - if err != nil { - log.Errorf(err.Error()) - return err - } - task.ErrorLogCount = count - - if err := ct.UpdateId(id, task); err != nil { - log.Errorf("update error log count error: " + err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -// convert all running tasks to abnormal tasks -func UpdateTaskToAbnormal(nodeId bson.ObjectId) error { - s, c := database.GetCol("tasks") - defer s.Close() - - selector := bson.M{ - "node_id": nodeId, - "status": bson.M{ - "$in": []string{ - constants.StatusPending, - constants.StatusRunning, - }, - }, - } - update := bson.M{ - "$set": bson.M{ - "status": constants.StatusAbnormal, - }, - } - _, err := c.UpdateAll(selector, update) - if err != nil { - log.Errorf("update task to abnormal error: %s, node_id : %s", err.Error(), nodeId.Hex()) - debug.PrintStack() - return err - } - return nil -} - -// update task error logs -func UpdateTaskErrorLogs(taskId string, errorRegexPattern string) error { - s, c := database.GetCol("logs") - defer s.Close() - - if errorRegexPattern == "" { - errorRegexPattern = constants.ErrorRegexPattern - } - - query := bson.M{ - "task_id": taskId, - "msg": bson.M{ - "$regex": bson.RegEx{ - Pattern: errorRegexPattern, - Options: "i", - }, - }, - } - var logs []LogItem - if err := c.Find(query).All(&logs); err != nil { - log.Errorf("find error logs error: " + err.Error()) - debug.PrintStack() - return err - } - - for _, l := range logs { - e := ErrorLogItem{ - Id: bson.NewObjectId(), - TaskId: l.TaskId, - Message: l.Message, - LogId: l.Id, - Seq: l.Seq, - Ts: time.Now(), - } - if err := AddErrorLogItem(e); err != nil { - return err - } - } - - return nil -} - -func GetTaskByFilter(filter bson.M) (t Task, err error) { - s, c := database.GetCol("tasks") - defer s.Close() - - if err := c.Find(filter).One(&t); err != nil { - if err != mgo.ErrNotFound { - log.Errorf("find task by filter error: " + err.Error()) - debug.PrintStack() - return t, err - } - return t, err - } - - return t, nil -} diff --git a/backend/model/token.go b/backend/model/token.go deleted file mode 100644 index b5763866..00000000 --- a/backend/model/token.go +++ /dev/null @@ -1,80 +0,0 @@ -package model - -import ( - "crawlab/database" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "runtime/debug" - "time" -) - -type Token struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - Token string `json:"token" bson:"token"` - UserId bson.ObjectId `json:"user_id" bson:"user_id"` - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` -} - -func (t *Token) Add() error { - s, c := database.GetCol("tokens") - defer s.Close() - - if err := c.Insert(t); err != nil { - log.Errorf("insert token error: " + err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func (t *Token) Delete() error { - s, c := database.GetCol("tokens") - defer s.Close() - - if err := c.RemoveId(t.Id); err != nil { - log.Errorf("insert token error: " + err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func GetTokenById(id bson.ObjectId) (t Token, err error) { - s, c := database.GetCol("tokens") - defer s.Close() - - if err = c.FindId(id).One(&t); err != nil { - return t, err - } - - return t, nil -} - -func GetTokensByUserId(uid bson.ObjectId) (tokens []Token, err error) { - s, c := database.GetCol("tokens") - defer s.Close() - - if err = c.Find(bson.M{"user_id": uid}).All(&tokens); err != nil { - log.Errorf("find tokens error: " + err.Error()) - debug.PrintStack() - return tokens, err - } - - return tokens, nil -} - -func DeleteTokenById(id bson.ObjectId) error { - t, err := GetTokenById(id) - if err != nil { - return err - } - - if err := t.Delete(); err != nil { - return err - } - - return nil -} diff --git a/backend/model/user.go b/backend/model/user.go deleted file mode 100644 index feb801cb..00000000 --- a/backend/model/user.go +++ /dev/null @@ -1,166 +0,0 @@ -package model - -import ( - "crawlab/database" - "crawlab/utils" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "github.com/pkg/errors" - "runtime/debug" - "time" -) - -type User struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - Username string `json:"username" bson:"username"` - Password string `json:"password" bson:"password"` - Role string `json:"role" bson:"role"` - Email string `json:"email" bson:"email"` - Setting UserSetting `json:"setting" bson:"setting"` - - UserId bson.ObjectId `json:"user_id" bson:"user_id"` - CreateTs time.Time `json:"create_ts" bson:"create_ts"` - UpdateTs time.Time `json:"update_ts" bson:"update_ts"` -} - -type UserSetting struct { - NotificationTrigger string `json:"notification_trigger" bson:"notification_trigger"` - DingTalkRobotWebhook string `json:"ding_talk_robot_webhook" bson:"ding_talk_robot_webhook"` - WechatRobotWebhook string `json:"wechat_robot_webhook" bson:"wechat_robot_webhook"` - EnabledNotifications []string `json:"enabled_notifications" bson:"enabled_notifications"` - ErrorRegexPattern string `json:"error_regex_pattern" bson:"error_regex_pattern"` - MaxErrorLog int `json:"max_error_log" bson:"max_error_log"` - LogExpireDuration int64 `json:"log_expire_duration" bson:"log_expire_duration"` -} - -func (user *User) Save() error { - s, c := database.GetCol("users") - defer s.Close() - - user.UpdateTs = time.Now() - - if err := c.UpdateId(user.Id, user); err != nil { - debug.PrintStack() - return err - } - return nil -} - -func (user *User) Add() error { - s, c := database.GetCol("users") - defer s.Close() - - // 如果存在用户名相同的用户,抛错 - user2, err := GetUserByUsername(user.Username) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - if user2.Username == user.Username { - return errors.New("username already exists") - } - - user.Id = bson.NewObjectId() - user.UpdateTs = time.Now() - user.CreateTs = time.Now() - if err := c.Insert(user); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func GetUser(id bson.ObjectId) (User, error) { - s, c := database.GetCol("users") - defer s.Close() - var user User - if err := c.Find(bson.M{"_id": id}).One(&user); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return user, err - } - return user, nil -} - -func GetUserByUsername(username string) (User, error) { - s, c := database.GetCol("users") - defer s.Close() - - var user User - if err := c.Find(bson.M{"username": username}).One(&user); err != nil { - if err != mgo.ErrNotFound { - log.Errorf(err.Error()) - debug.PrintStack() - return user, err - } - } - - return user, nil -} - -func GetUserList(filter interface{}, skip int, limit int, sortKey string) ([]User, error) { - s, c := database.GetCol("users") - defer s.Close() - - var users []User - if err := c.Find(filter).Skip(skip).Limit(limit).Sort(sortKey).All(&users); err != nil { - debug.PrintStack() - return users, err - } - return users, nil -} - -func GetUserListTotal(filter interface{}) (int, error) { - s, c := database.GetCol("users") - defer s.Close() - - var result int - result, err := c.Find(filter).Count() - if err != nil { - return result, err - } - return result, nil -} - -func UpdateUser(id bson.ObjectId, item User) error { - s, c := database.GetCol("users") - defer s.Close() - - var result User - if err := c.FindId(id).One(&result); err != nil { - debug.PrintStack() - return err - } - - if item.Password == "" { - item.Password = result.Password - } else { - item.Password = utils.EncryptPassword(item.Password) - } - - if err := item.Save(); err != nil { - return err - } - return nil -} - -func RemoveUser(id bson.ObjectId) error { - s, c := database.GetCol("users") - defer s.Close() - - var result User - if err := c.FindId(id).One(&result); err != nil { - return err - } - - if err := c.RemoveId(id); err != nil { - return err - } - - return nil -} diff --git a/backend/model/variable.go b/backend/model/variable.go deleted file mode 100644 index 3af2188e..00000000 --- a/backend/model/variable.go +++ /dev/null @@ -1,97 +0,0 @@ -package model - -import ( - "crawlab/database" - "errors" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "runtime/debug" -) - -/** -全局变量 -*/ - -type Variable struct { - Id bson.ObjectId `json:"_id" bson:"_id"` - Key string `json:"key" bson:"key"` - Value string `json:"value" bson:"value"` - Remark string `json:"remark" bson:"remark"` -} - -func (model *Variable) Save() error { - s, c := database.GetCol("variable") - defer s.Close() - - if err := c.UpdateId(model.Id, model); err != nil { - log.Errorf("update variable error: %s", err.Error()) - return err - } - return nil -} - -func (model *Variable) Add() error { - s, c := database.GetCol("variable") - defer s.Close() - - // key 去重 - _, err := GetByKey(model.Key) - if err == nil { - return errors.New("key already exists") - } - - model.Id = bson.NewObjectId() - if err := c.Insert(model); err != nil { - log.Errorf("add variable error: %s", err.Error()) - debug.PrintStack() - return err - } - return nil -} - -func (model *Variable) Delete() error { - s, c := database.GetCol("variable") - defer s.Close() - - if err := c.RemoveId(model.Id); err != nil { - log.Errorf("remove variable error: %s", err.Error()) - debug.PrintStack() - return err - } - return nil -} - -func GetByKey(key string) (Variable, error) { - s, c := database.GetCol("variable") - defer s.Close() - - var model Variable - if err := c.Find(bson.M{"key": key}).One(&model); err != nil { - log.Errorf("variable found error: %s, key: %s", err.Error(), key) - return model, err - } - return model, nil -} - -func GetVariable(id bson.ObjectId) (Variable, error) { - s, c := database.GetCol("variable") - defer s.Close() - - var model Variable - if err := c.FindId(id).One(&model); err != nil { - log.Errorf("variable found error: %s", err.Error()) - return model, err - } - return model, nil -} - -func GetVariableList() []Variable { - s, c := database.GetCol("variable") - defer s.Close() - - var list []Variable - if err := c.Find(nil).All(&list); err != nil { - - } - return list -} diff --git a/backend/routes/action.go b/backend/routes/action.go deleted file mode 100644 index 19144a4e..00000000 --- a/backend/routes/action.go +++ /dev/null @@ -1,118 +0,0 @@ -package routes - -import ( - "crawlab/model" - "crawlab/services" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" -) - -func GetAction(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - user, err := model.GetAction(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: user, - }) -} - -func GetActionList(c *gin.Context) { - pageNum := c.GetInt("page_num") - pageSize := c.GetInt("page_size") - - users, err := model.GetActionList(nil, (pageNum-1)*pageSize, pageSize, "-create_ts") - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - total, err := model.GetActionListTotal(nil) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, ListResponse{ - Status: "ok", - Message: "success", - Data: users, - Total: total, - }) -} - -func PutAction(c *gin.Context) { - // 绑定请求数据 - var action model.Action - if err := c.ShouldBindJSON(&action); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - action.UserId = services.GetCurrentUserId(c) - - if err := action.Add(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func PostAction(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - var item model.Action - if err := c.ShouldBindJSON(&item); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - if err := model.UpdateAction(bson.ObjectIdHex(id), item); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func DeleteAction(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - // 从数据库中删除该爬虫 - if err := model.RemoveAction(bson.ObjectIdHex(id)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/routes/base.go b/backend/routes/base.go deleted file mode 100644 index 0204b0ea..00000000 --- a/backend/routes/base.go +++ /dev/null @@ -1,24 +0,0 @@ -package routes - -type Response struct { - Status string `json:"status"` - Message string `json:"message"` - Data interface{} `json:"data"` - Error string `json:"error"` -} - -type ListResponse struct { - Status string `json:"status"` - Message string `json:"message"` - Total int `json:"total"` - Data interface{} `json:"data"` - Error string `json:"error"` -} - -type ListRequestData struct { - PageNum int `form:"page_num" json:"page_num"` - PageSize int `form:"page_size" json:"page_size"` - SortKey string `form:"sort_key" json:"sort_key"` - Status string `form:"status" json:"status"` - Keyword string `form:"keyword" json:"keyword"` -} diff --git a/backend/routes/challenge.go b/backend/routes/challenge.go deleted file mode 100644 index 1f03654a..00000000 --- a/backend/routes/challenge.go +++ /dev/null @@ -1,45 +0,0 @@ -package routes - -import ( - "crawlab/constants" - "crawlab/model" - "crawlab/services" - "crawlab/services/challenge" - "github.com/gin-gonic/gin" - "net/http" -) - -func GetChallengeList(c *gin.Context) { - // 获取列表 - users, err := model.GetChallengeListWithAchieved(nil, 0, constants.Infinite, "create_ts", services.GetCurrentUserId(c)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取总数 - total, err := model.GetChallengeListTotal(nil) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, ListResponse{ - Status: "ok", - Message: "success", - Data: users, - Total: total, - }) -} - -func CheckChallengeList(c *gin.Context) { - uid := services.GetCurrentUserId(c) - if err := challenge.CheckChallengeAndUpdateAll(uid); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/routes/config_spider.go b/backend/routes/config_spider.go deleted file mode 100644 index 93b5c7f9..00000000 --- a/backend/routes/config_spider.go +++ /dev/null @@ -1,411 +0,0 @@ -package routes - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/model" - "crawlab/services" - "crawlab/utils" - "fmt" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "github.com/spf13/viper" - "gopkg.in/yaml.v2" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "strings" -) - -// 添加可配置爬虫 - -// @Summary Put config spider -// @Description Put config spider -// @Tags config spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param spider body model.Spider true "spider item" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /config_spiders [put] -func PutConfigSpider(c *gin.Context) { - var spider model.Spider - if err := c.ShouldBindJSON(&spider); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 爬虫名称不能为空 - if spider.Name == "" { - HandleErrorF(http.StatusBadRequest, c, "spider name should not be empty") - return - } - - // 模版名不能为空 - if spider.Template == "" { - HandleErrorF(http.StatusBadRequest, c, "spider template should not be empty") - return - } - - // 判断爬虫是否存在 - if spider := model.GetSpiderByName(spider.Name); spider.Name != "" { - HandleErrorF(http.StatusBadRequest, c, fmt.Sprintf("spider for '%s' already exists", spider.Name)) - return - } - - // 设置爬虫类别 - spider.Type = constants.Configurable - - // 将FileId置空 - spider.FileId = bson.ObjectIdHex(constants.ObjectIdNull) - - // UserId - spider.UserId = services.GetCurrentUserId(c) - - // 创建爬虫目录 - spiderDir := filepath.Join(viper.GetString("spider.path"), spider.Name) - if utils.Exists(spiderDir) { - if err := os.RemoveAll(spiderDir); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - if err := os.MkdirAll(spiderDir, 0777); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - spider.Src = spiderDir - - // 复制Spiderfile模版 - contentByte, err := ioutil.ReadFile("./template/spiderfile/Spiderfile." + spider.Template) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - f, err := os.Create(filepath.Join(spider.Src, "Spiderfile")) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - defer f.Close() - if _, err := f.Write(contentByte); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 添加爬虫到数据库 - if err := spider.Add(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: spider, - }) -} - -// 更改可配置爬虫 -func PostConfigSpider(c *gin.Context) { - PostSpider(c) -} - -// 上传可配置爬虫Spiderfile - -// @Summary Upload config spider -// @Description Upload config spider -// @Tags config spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param spider body model.Spider true "spider item" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /config_spiders/{id}/upload [post] -func UploadConfigSpider(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 获取爬虫 - var spider model.Spider - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleErrorF(http.StatusBadRequest, c, fmt.Sprintf("cannot find spider (id: %s)", id)) - return - } - - // UserId - spider.UserId = services.GetCurrentUserId(c) - - // 获取上传文件 - file, header, err := c.Request.FormFile("file") - if err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 文件名称必须为Spiderfile - filename := header.Filename - if filename != "Spiderfile" && filename != "Spiderfile.yaml" && filename != "Spiderfile.yml" { - HandleErrorF(http.StatusBadRequest, c, "filename must be 'Spiderfile(.yaml|.yml)'") - return - } - - // 爬虫目录 - spiderDir := filepath.Join(viper.GetString("spider.path"), spider.Name) - - // 爬虫Spiderfile文件路径 - sfPath := filepath.Join(spiderDir, filename) - - // 创建(如果不存在)或打开Spiderfile(如果存在) - var f *os.File - if utils.Exists(sfPath) { - f, err = os.OpenFile(sfPath, os.O_WRONLY, 0777) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } else { - f, err = os.Create(sfPath) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 将上传的文件拷贝到爬虫Spiderfile文件 - _, err = io.Copy(f, file) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 关闭Spiderfile文件 - _ = f.Close() - - // 构造配置数据 - configData := entity.ConfigSpiderData{} - - // 读取YAML文件 - yamlFile, err := ioutil.ReadFile(sfPath) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 反序列化 - if err := yaml.Unmarshal(yamlFile, &configData); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 根据序列化后的数据处理爬虫文件 - if err := services.ProcessSpiderFilesFromConfigData(spider, configData); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Post config spider -// @Description Post config spider -// @Tags config spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /config_spiders/{id}/spiderfile [post] -func PostConfigSpiderSpiderfile(c *gin.Context) { - type Body struct { - Content string `json:"content"` - } - - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 文件内容 - var reqBody Body - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - content := reqBody.Content - - // 获取爬虫 - var spider model.Spider - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleErrorF(http.StatusBadRequest, c, fmt.Sprintf("cannot find spider (id: %s)", id)) - return - } - - // UserId - if !spider.UserId.Valid() { - spider.UserId = bson.ObjectIdHex(constants.ObjectIdNull) - } - - // 反序列化 - var configData entity.ConfigSpiderData - if err := yaml.Unmarshal([]byte(content), &configData); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 校验configData - if err := services.ValidateSpiderfile(configData); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 写文件 - if err := ioutil.WriteFile(filepath.Join(spider.Src, "Spiderfile"), []byte(content), os.ModePerm); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 根据序列化后的数据处理爬虫文件 - if err := services.ProcessSpiderFilesFromConfigData(spider, configData); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Post config spider config -// @Description Post config spider config -// @Tags config spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param spider body model.Spider true "spider item" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /config_spiders/{id}/config [post] -func PostConfigSpiderConfig(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 获取爬虫 - var spider model.Spider - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleErrorF(http.StatusBadRequest, c, fmt.Sprintf("cannot find spider (id: %s)", id)) - return - } - - // UserId - if !spider.UserId.Valid() { - spider.UserId = bson.ObjectIdHex(constants.ObjectIdNull) - } - - // 反序列化配置数据 - var configData entity.ConfigSpiderData - if err := c.ShouldBindJSON(&configData); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 校验configData - if err := services.ValidateSpiderfile(configData); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 替换Spiderfile文件 - if err := services.GenerateSpiderfileFromConfigData(spider, configData); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 根据序列化后的数据处理爬虫文件 - if err := services.ProcessSpiderFilesFromConfigData(spider, configData); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Get config spider -// @Description Get config spider -// @Tags config spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /config_spiders/{id}/config [get] -func GetConfigSpiderConfig(c *gin.Context) { - id := c.Param("id") - - // 校验ID - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - // 获取爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: spider.Config, - }) -} - -// 获取模版名称列表 - -// @Summary Get config spider template list -// @Description Get config spider template list -// @Tags config spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /config_spiders_templates [get] -func GetConfigSpiderTemplateList(c *gin.Context) { - var data []string - for _, fInfo := range utils.ListDir("./template/spiderfile") { - templateName := strings.Replace(fInfo.Name(), "Spiderfile.", "", -1) - data = append(data, templateName) - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: data, - }) -} diff --git a/backend/routes/doc.go b/backend/routes/doc.go deleted file mode 100644 index f38c5431..00000000 --- a/backend/routes/doc.go +++ /dev/null @@ -1,33 +0,0 @@ -package routes - -import ( - "crawlab/services" - "github.com/apex/log" - "github.com/gin-gonic/gin" - "net/http" - "runtime/debug" -) - -// @Summary Get docs -// @Description Get docs -// @Tags docs -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /docs [get] -func GetDocs(c *gin.Context) { - type ResData struct { - String string `json:"string"` - } - data, err := services.GetDocs() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: ResData{String:data}, - }) -} diff --git a/backend/routes/file.go b/backend/routes/file.go deleted file mode 100644 index 4c9f8576..00000000 --- a/backend/routes/file.go +++ /dev/null @@ -1,29 +0,0 @@ -package routes - -import ( - "crawlab/utils" - "github.com/gin-gonic/gin" - "io/ioutil" - "net/http" -) - -// @Summary Get file -// @Description Get file -// @Tags file -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /file [get] -func GetFile(c *gin.Context) { - path := c.Query("path") - fileBytes, err := ioutil.ReadFile(path) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: utils.BytesToString(fileBytes), - }) -} diff --git a/backend/routes/git.go b/backend/routes/git.go deleted file mode 100644 index aa889be2..00000000 --- a/backend/routes/git.go +++ /dev/null @@ -1,84 +0,0 @@ -package routes - -import ( - "crawlab/model" - "crawlab/services" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" -) - -func GetGitRemoteBranches(c *gin.Context) { - url := c.Query("url") - username := c.Query("username") - password := c.Query("password") - branches, err := services.GetGitRemoteBranchesPlain(url, username, password) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: branches, - }) -} - -func GetGitSshPublicKey(c *gin.Context) { - content := services.GetGitSshPublicKey() - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: content, - }) -} - -func GetGitCommits(c *gin.Context) { - spiderId := c.Query("spider_id") - if spiderId == "" || !bson.IsObjectIdHex(spiderId) { - HandleErrorF(http.StatusInternalServerError, c, "invalid request") - return - } - spider, err := model.GetSpider(bson.ObjectIdHex(spiderId)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - commits, err := services.GetGitCommits(spider) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: commits, - }) -} - -func PostGitCheckout(c *gin.Context) { - type ReqBody struct { - SpiderId string `json:"spider_id"` - Hash string `json:"hash"` - } - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - } - if reqBody.SpiderId == "" || !bson.IsObjectIdHex(reqBody.SpiderId) { - HandleErrorF(http.StatusInternalServerError, c, "invalid request") - return - } - spider, err := model.GetSpider(bson.ObjectIdHex(reqBody.SpiderId)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - if err := services.GitCheckout(spider, reqBody.Hash); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/routes/market.go b/backend/routes/market.go deleted file mode 100644 index 0db51ae5..00000000 --- a/backend/routes/market.go +++ /dev/null @@ -1 +0,0 @@ -package routes diff --git a/backend/routes/node.go b/backend/routes/node.go deleted file mode 100644 index 434e1b33..00000000 --- a/backend/routes/node.go +++ /dev/null @@ -1,198 +0,0 @@ -package routes - -import ( - "crawlab/model" - "crawlab/services" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" -) - -// @Summary Get nodes -// @Description Get nodes -// @Tags node -// @Produce json -// @Param Authorization header string true "With the bearer started" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes [get] -func GetNodeList(c *gin.Context) { - nodes, err := model.GetNodeList(nil) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - //for i, node := range nodes { - // nodes[i].IsMaster = services.IsMasterNode(node.Id.Hex()) - //} - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: nodes, - }) -} - -// @Summary Get node -// @Description Get node -// @Tags node -// @Produce json -// @Param Authorization header string true "With the bearer started" -// @Param id path string true "id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id} [get] -func GetNode(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - result, err := model.GetNode(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: result, - }) -} - -func Ping(c *gin.Context) { - data, err := services.GetNodeData() - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: data, - }) -} - -// @Summary Post node -// @Description Post node -// @Tags node -// @Accept json -// @Produce json -// @Param Authorization header string true "With the bearer started" -// @Param id path string true "post node" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /nodes/{id} [post] -func PostNode(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - item, err := model.GetNode(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - var newItem model.Node - if err := c.ShouldBindJSON(&newItem); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - newItem.Id = item.Id - - if err := model.UpdateNode(bson.ObjectIdHex(id), newItem); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Get tasks on node -// @Description Get tasks on node -// @Tags node -// @Produce json -// @Param Authorization header string true "With the bearer started" -// @Param id path string true "node id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id}/tasks [get] -func GetNodeTaskList(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - tasks, err := model.GetNodeTaskList(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: tasks, - }) -} - -// @Summary Get system info -// @Description Get system info -// @Tags node -// @Produce json -// @Param Authorization header string true "With the bearer started" -// @Param id path string true "node id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id}/system [get] -func GetSystemInfo(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - sysInfo, _ := services.GetSystemInfo(id) - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: sysInfo, - }) -} - -// @Summary Delete node -// @Description Delete node -// @Tags node -// @Produce json -// @Param Authorization header string true "With the bearer started" -// @Param id path string true "node id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id} [delete] -func DeleteNode(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - node, err := model.GetNode(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - err = node.Delete() - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/routes/project.go b/backend/routes/project.go deleted file mode 100644 index 7a62d31a..00000000 --- a/backend/routes/project.go +++ /dev/null @@ -1,245 +0,0 @@ -package routes - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/model" - "crawlab/services" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" -) - -// @Summary Get projects -// @Description Get projects -// @Tags project -// @Produce json -// @Param Authorization header string true "With the bearer started" -// @Param tag query string true "projects" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /projects [get] -func GetProjectList(c *gin.Context) { - tag := c.Query("tag") - - // 筛选条件 - query := bson.M{} - if tag != "" { - query["tags"] = tag - } - - // 获取校验 - query = services.GetAuthQuery(query, c) - - // 获取列表 - projects, err := model.GetProjectList(query, "+_id") - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取总数 - total, err := model.GetProjectListTotal(query) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取每个项目的爬虫列表 - for i, p := range projects { - spiders, err := p.GetSpiders() - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - projects[i].Spiders = spiders - } - - // 获取未被分配的爬虫数量 - if tag == "" { - noProject := model.Project{ - Id: bson.ObjectIdHex(constants.ObjectIdNull), - Name: "No Project", - Description: "Not assigned to any project", - } - spiders, err := noProject.GetSpiders() - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - noProject.Spiders = spiders - projects = append(projects, noProject) - } - - c.JSON(http.StatusOK, ListResponse{ - Status: "ok", - Message: "success", - Data: projects, - Total: total, - }) -} - -// @Summary Put project -// @Description Put project -// @Tags project -// @Accept json -// @Produce json -// @Param Authorization header string true "With the bearer started" -// @Param p body model.Project true "post project" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /projects [put] -func PutProject(c *gin.Context) { - // 绑定请求数据 - var p model.Project - if err := c.ShouldBindJSON(&p); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // UserId - p.UserId = services.GetCurrentUserId(c) - - if err := p.Add(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Post project -// @Description Post project -// @Tags project -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "project id" -// @Param item body model.Project true "project item" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /projects/{id} [post] -func PostProject(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - var item model.Project - if err := c.ShouldBindJSON(&item); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - if err := model.UpdateProject(bson.ObjectIdHex(id), item); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Delete project -// @Description Delete project -// @Tags project -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "project id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /projects/{id} [delete] -func DeleteProject(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - // 从数据库中删除该爬虫 - if err := model.RemoveProject(bson.ObjectIdHex(id)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取相关的爬虫 - var spiders []model.Spider - s, col := database.GetCol("spiders") - defer s.Close() - if err := col.Find(bson.M{"project_id": bson.ObjectIdHex(id)}).All(&spiders); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 将爬虫的项目ID置空 - for _, spider := range spiders { - spider.ProjectId = bson.ObjectIdHex(constants.ObjectIdNull) - if err := spider.Save(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Get project tags -// @Description Get projects tags -// @Tags project -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /projects/tags [get] -func GetProjectTags(c *gin.Context) { - type Result struct { - Tag string `json:"tag" bson:"tag"` - } - - s, col := database.GetCol("projects") - defer s.Close() - - pipeline := []bson.M{ - { - "$unwind": "$tags", - }, - { - "$group": bson.M{ - "_id": "$tags", - }, - }, - { - "$sort": bson.M{ - "_id": 1, - }, - }, - { - "$addFields": bson.M{ - "tag": "$_id", - }, - }, - } - - var items []Result - if err := col.Pipe(pipeline).All(&items); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: items, - }) -} diff --git a/backend/routes/repos.go b/backend/routes/repos.go deleted file mode 100644 index 00a4e847..00000000 --- a/backend/routes/repos.go +++ /dev/null @@ -1,81 +0,0 @@ -package routes - -import ( - "crawlab/services" - "fmt" - "github.com/apex/log" - "github.com/gin-gonic/gin" - "github.com/imroc/req" - "github.com/spf13/viper" - "net/http" - "runtime/debug" -) - -func GetRepoList(c *gin.Context) { - var data ListRequestData - if err := c.ShouldBindQuery(&data); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - params := req.Param{ - "page_num": data.PageNum, - "page_size": data.PageSize, - "keyword": data.Keyword, - "sort_key": data.SortKey, - } - res, err := req.Get(fmt.Sprintf("%s/public/repos", viper.GetString("repo.apiUrl")), params) - if err != nil { - log.Error("get repos error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - var resJson interface{} - if err := res.ToJSON(&resJson); err != nil { - log.Error("to json error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, resJson) -} - -func GetRepoSubDirList(c *gin.Context) { - params := req.Param{ - "full_name": c.Query("full_name"), - } - res, err := req.Get(fmt.Sprintf("%s/public/repos/sub-dir", viper.GetString("repo.apiUrl")), params) - if err != nil { - log.Error("get repo sub-dir error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - var resJson interface{} - if err := res.ToJSON(&resJson); err != nil { - log.Error("to json error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, resJson) -} - -func DownloadRepo(c *gin.Context) { - type RequestData struct { - FullName string `json:"full_name"` - } - var reqData RequestData - if err := c.ShouldBindJSON(&reqData); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - if err := services.DownloadRepo(reqData.FullName, services.GetCurrentUserId(c)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/routes/schedule.go b/backend/routes/schedule.go deleted file mode 100644 index 5da735e0..00000000 --- a/backend/routes/schedule.go +++ /dev/null @@ -1,323 +0,0 @@ -package routes - -import ( - "crawlab/model" - "crawlab/services" - "github.com/apex/log" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" - "runtime/debug" -) - -// @Summary Get schedule list -// @Description Get schedule list -// @Tags schedule -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /schedules [get] -func GetScheduleList(c *gin.Context) { - query := bson.M{} - - // 获取校验 - query = services.GetAuthQuery(query, c) - - results, err := model.GetScheduleList(query) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccessData(c, results) -} - -// @Summary Get schedule by id -// @Description Get schedule by id -// @Tags schedule -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "schedule id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /schedules/{id} [get] -func GetSchedule(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - result, err := model.GetSchedule(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - HandleSuccessData(c, result) -} - -// @Summary Post schedule -// @Description Post schedule -// @Tags schedule -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "schedule id" -// @Param newItem body model.Schedule true "schedule item" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /schedules/{id} [post] -func PostSchedule(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 绑定数据模型 - var newItem model.Schedule - if err := c.ShouldBindJSON(&newItem); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 验证cron表达式 - if err := services.ParserCron(newItem.Cron); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - newItem.Id = bson.ObjectIdHex(id) - // 更新数据库 - if err := model.UpdateSchedule(bson.ObjectIdHex(id), newItem); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 更新定时任务 - if err := services.Sched.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - HandleSuccess(c) -} - -// @Summary Put schedule -// @Description Put schedule -// @Tags schedule -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param item body model.Schedule true "schedule item" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /schedules [put] -func PutSchedule(c *gin.Context) { - var item model.Schedule - - // 绑定数据模型 - if err := c.ShouldBindJSON(&item); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 验证cron表达式 - if err := services.ParserCron(item.Cron); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 加入用户ID - item.UserId = services.GetCurrentUserId(c) - - // 更新数据库 - if err := model.AddSchedule(item); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 更新定时任务 - if err := services.Sched.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - HandleSuccess(c) -} - -// @Summary Delete schedule -// @Description Delete schedule -// @Tags schedule -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "schedule id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /schedules/{id} [delete] -func DeleteSchedule(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 删除定时任务 - if err := model.RemoveSchedule(bson.ObjectIdHex(id)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 更新定时任务 - if err := services.Sched.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - HandleSuccess(c) -} - -// 停止定时任务 -// @Summary disable schedule -// @Description disable schedule -// @Tags schedule -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "schedule id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /schedules/{id}/disable [post] -func DisableSchedule(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - if err := services.Sched.Disable(bson.ObjectIdHex(id)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccess(c) -} - -// 运行定时任务 -// @Summary enable schedule -// @Description enable schedule -// @Tags schedule -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "schedule id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /schedules/{id}/enable [post] -func EnableSchedule(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - if err := services.Sched.Enable(bson.ObjectIdHex(id)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccess(c) -} - -func PutBatchSchedules(c *gin.Context) { - var schedules []model.Schedule - if err := c.ShouldBindJSON(&schedules); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - for _, s := range schedules { - // 验证cron表达式 - if err := services.ParserCron(s.Cron); err != nil { - log.Errorf("parse cron error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 添加 UserID - s.UserId = services.GetCurrentUserId(c) - - // 默认启用 - s.Enabled = true - - // 添加定时任务 - if err := model.AddSchedule(s); err != nil { - log.Errorf("add schedule error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 更新定时任务 - if err := services.Sched.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - HandleSuccess(c) -} - -func DeleteBatchSchedules(c *gin.Context) { - ids := make(map[string][]string) - if err := c.ShouldBindJSON(&ids); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - list := ids["ids"] - for _, id := range list { - if err := model.RemoveSchedule(bson.ObjectIdHex(id)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 更新定时任务 - if err := services.Sched.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - HandleSuccess(c) -} - -func SetEnabledSchedules(c *gin.Context) { - type ReqBody struct { - ScheduleIds []bson.ObjectId `json:"schedule_ids"` - Enabled bool `json:"enabled"` - } - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - for _, id := range reqBody.ScheduleIds { - s, err := model.GetSchedule(id) - if err != nil { - log.Errorf("get schedule error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - s.Enabled = reqBody.Enabled - if err := s.Save(); err != nil { - log.Errorf("save schedule error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 更新定时任务 - if err := services.Sched.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - HandleSuccess(c) -} diff --git a/backend/routes/setting.go b/backend/routes/setting.go deleted file mode 100644 index 5faea750..00000000 --- a/backend/routes/setting.go +++ /dev/null @@ -1,55 +0,0 @@ -package routes - -import ( - "github.com/gin-gonic/gin" - "github.com/spf13/viper" - "net/http" -) - -type SettingBody struct { - AllowRegister string `json:"allow_register"` - EnableTutorial string `json:"enable_tutorial"` - RunOnMaster string `json:"run_on_master"` - EnableDemoSpiders string `json:"enable_demo_spiders"` -} - -// @Summary Get version -// @Description Get version -// @Tags setting -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /version [get] -func GetVersion(c *gin.Context) { - version := viper.GetString("version") - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: version, - }) -} - -// @Summary Get setting -// @Description Get setting -// @Tags setting -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /setting [get] -func GetSetting(c *gin.Context) { - body := SettingBody{ - AllowRegister: viper.GetString("setting.allowRegister"), - EnableTutorial: viper.GetString("setting.enableTutorial"), - RunOnMaster: viper.GetString("setting.runOnMaster"), - EnableDemoSpiders: viper.GetString("setting.enableDemoSpiders"), - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: body, - }) -} diff --git a/backend/routes/spider.go b/backend/routes/spider.go deleted file mode 100644 index 87ec7c26..00000000 --- a/backend/routes/spider.go +++ /dev/null @@ -1,1910 +0,0 @@ -package routes - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/entity" - "crawlab/model" - "crawlab/services" - "crawlab/utils" - "fmt" - "github.com/apex/log" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "github.com/pkg/errors" - "github.com/satori/go.uuid" - "github.com/spf13/viper" - "io/ioutil" - "net/http" - "os" - "path" - "path/filepath" - "runtime/debug" - "strconv" - "strings" - "time" -) - -// ======== 爬虫管理 ======== - -// @Summary Get spider list -// @Description Get spider list -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param page_num query string false "page num" -// @Param page_size query string false "page size" -// @Param keyword query string false "keyword" -// @Param project_id query string false "project_id" -// @Param type query string false "type" -// @Param sort_key query string false "sort_key" -// @Param sort_direction query string false "sort_direction" -// @Param owner_type query string false "owner_type" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /schedules [get] -func GetSpiderList(c *gin.Context) { - pageNum := c.Query("page_num") - pageSize := c.Query("page_size") - keyword := c.Query("keyword") - pid := c.Query("project_id") - t := c.Query("type") - sortKey := c.Query("sort_key") - sortDirection := c.Query("sort_direction") - ownerType := c.Query("owner_type") - - // 筛选-名称 - filter := bson.M{ - "name": bson.M{"$regex": bson.RegEx{Pattern: keyword, Options: "im"}}, - } - - // 筛选-类型 - if t != "" && t != "all" { - filter["type"] = t - } - - // 筛选-是否为长任务 - if t == "long-task" { - delete(filter, "type") - filter["is_long_task"] = true - } - - // 筛选-项目 - if pid == "" { - // do nothing - } else if pid == constants.ObjectIdNull { - filter["$or"] = []bson.M{ - {"project_id": bson.ObjectIdHex(pid)}, - {"project_id": bson.M{"$exists": false}}, - } - } else { - filter["project_id"] = bson.ObjectIdHex(pid) - } - - // 筛选-用户 - if ownerType == constants.OwnerTypeAll { - user := services.GetCurrentUser(c) - if user.Role == constants.RoleNormal { - filter["$or"] = []bson.M{ - {"user_id": services.GetCurrentUserId(c)}, - {"is_public": true}, - } - } - } else if ownerType == constants.OwnerTypeMe { - filter["user_id"] = services.GetCurrentUserId(c) - } else if ownerType == constants.OwnerTypePublic { - filter["is_public"] = true - } - - // 排序 - sortStr := "-_id" - if sortKey != "" && sortDirection != "" { - if sortDirection == constants.DESCENDING { - sortStr = "-" + sortKey - } else if sortDirection == constants.ASCENDING { - sortStr = "+" + sortKey - } else { - HandleErrorF(http.StatusBadRequest, c, "invalid sort_direction") - return - } - } - - // 分页 - page := &entity.Page{} - page.GetPage(pageNum, pageSize) - - results, count, err := model.GetSpiderList(filter, page.Skip, page.Limit, sortStr) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: bson.M{"list": results, "total": count}, - }) -} - -// @Summary Get spider by id -// @Description Get spider by id -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "schedule id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id} [get] -func GetSpider(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: spider, - }) -} - -// @Summary Post spider -// @Description Post spider -// @Tags spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "schedule id" -// @Param item body model.Spider true "spider item" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /spiders/{id} [post] -func PostSpider(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - var item model.Spider - if err := c.ShouldBindJSON(&item); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // UserId - if !item.UserId.Valid() { - item.UserId = bson.ObjectIdHex(constants.ObjectIdNull) - } - - if err := model.UpdateSpider(bson.ObjectIdHex(id), item); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 更新 GitCron - if err := services.GitCron.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 去重处理 - if err := services.UpdateSpiderDedup(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Publish spider -// @Description Publish spider -// @Tags spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "schedule id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /spiders/{id}/publish [post] -func PublishSpider(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - services.PublishSpider(spider) - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Put spider -// @Description Put spider -// @Tags spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param spider body model.Spider true "spider item" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /spiders [put] -func PutSpider(c *gin.Context) { - var spider model.Spider - if err := c.ShouldBindJSON(&spider); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 爬虫名称不能为空 - if spider.Name == "" { - HandleErrorF(http.StatusBadRequest, c, "spider name should not be empty") - return - } - - // 判断爬虫是否存在 - if spider := model.GetSpiderByName(spider.Name); spider.Name != "" { - HandleErrorF(http.StatusBadRequest, c, fmt.Sprintf("spider for '%s' already exists", spider.Name)) - return - } - - // 设置爬虫类别 - spider.Type = constants.Customized - - // 将FileId置空 - spider.FileId = bson.ObjectIdHex(constants.ObjectIdNull) - - // UserId - spider.UserId = services.GetCurrentUserId(c) - - // 爬虫目录 - spiderDir := filepath.Join(viper.GetString("spider.path"), spider.Name) - - // 赋值到爬虫实例 - spider.Src = spiderDir - - // 移除已有爬虫目录 - if utils.Exists(spiderDir) { - if err := os.RemoveAll(spiderDir); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 生成爬虫目录 - if err := os.MkdirAll(spiderDir, 0777); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 如果为 Scrapy 项目,生成 Scrapy 项目 - if spider.IsScrapy { - if err := services.CreateScrapyProject(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 添加爬虫到数据库 - if err := spider.Add(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 同步到GridFS - if err := services.UploadSpiderToGridFsFromMaster(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 更新 GitCron - if err := services.GitCron.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: spider, - }) -} - -// @Summary Copy spider -// @Description Copy spider -// @Tags spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "schedule id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /spiders/{id}/copy [post] -func CopySpider(c *gin.Context) { - type ReqBody struct { - Name string `json:"name"` - } - - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 检查新爬虫名称是否存在 - // 如果存在,则返回错误 - s := model.GetSpiderByName(reqBody.Name) - if s.Name != "" { - HandleErrorF(http.StatusBadRequest, c, fmt.Sprintf("spider name '%s' already exists", reqBody.Name)) - return - } - - // 被复制爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // UserId - spider.UserId = services.GetCurrentUserId(c) - - // 复制爬虫 - if err := services.CopySpider(spider, reqBody.Name); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Upload spider -// @Description Upload spider -// @Tags spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param file formData file true "spider file to upload" -// @Param name formData string true "spider name" -// @Param display_name formData string true "display name" -// @Param col formData string true "col" -// @Param cmd formData string true "cmd" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /spiders [post] -func UploadSpider(c *gin.Context) { - // 从body中获取文件 - uploadFile, err := c.FormFile("file") - if err != nil { - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取参数 - name := c.PostForm("name") - displayName := c.PostForm("display_name") - col := c.PostForm("col") - cmd := c.PostForm("cmd") - - // 如果不为zip文件,返回错误 - if !strings.HasSuffix(uploadFile.Filename, ".zip") { - HandleError(http.StatusBadRequest, c, errors.New("not a valid zip file")) - return - } - - // 以防tmp目录不存在 - tmpPath := viper.GetString("other.tmppath") - if !utils.Exists(tmpPath) { - if err := os.MkdirAll(tmpPath, os.ModePerm); err != nil { - log.Error("mkdir other.tmppath dir error:" + err.Error()) - debug.PrintStack() - HandleError(http.StatusBadRequest, c, errors.New("mkdir other.tmppath dir error")) - return - } - } - - // 保存到本地临时文件 - randomId := uuid.NewV4() - tmpFilePath := filepath.Join(tmpPath, randomId.String()+".zip") - if err := c.SaveUploadedFile(uploadFile, tmpFilePath); err != nil { - log.Error("save upload file error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取 GridFS 实例 - s, gf := database.GetGridFs("files") - defer s.Close() - - // 判断文件是否已经存在 - var gfFile model.GridFs - if err := gf.Find(bson.M{"filename": uploadFile.Filename}).One(&gfFile); err == nil { - // 已经存在文件,则删除 - if err := gf.RemoveId(gfFile.Id); err != nil { - log.Errorf("remove grid fs error: %s", err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 上传到GridFs - fid, err := services.RetryUploadToGridFs(uploadFile.Filename, tmpFilePath) - if err != nil { - log.Errorf("upload to grid fs error: %s", err.Error()) - debug.PrintStack() - return - } - - idx := strings.LastIndex(uploadFile.Filename, "/") - targetFilename := uploadFile.Filename[idx+1:] - - // 判断爬虫是否存在 - spiderName := strings.Replace(targetFilename, ".zip", "", 1) - if name != "" { - spiderName = name - } - spider := model.GetSpiderByName(spiderName) - if spider.Name == "" { - // 保存爬虫信息 - srcPath := viper.GetString("spider.path") - spider := model.Spider{ - Name: spiderName, - DisplayName: spiderName, - Type: constants.Customized, - Src: filepath.Join(srcPath, spiderName), - FileId: fid, - ProjectId: bson.ObjectIdHex(constants.ObjectIdNull), - UserId: services.GetCurrentUserId(c), - } - if name != "" { - spider.Name = name - } - if displayName != "" { - spider.DisplayName = displayName - } - if col != "" { - spider.Col = col - } - if cmd != "" { - spider.Cmd = cmd - } - if err := spider.Add(); err != nil { - log.Error("add spider error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - } else { - if name != "" { - spider.Name = name - } - if displayName != "" { - spider.DisplayName = displayName - } - if col != "" { - spider.Col = col - } - if cmd != "" { - spider.Cmd = cmd - } - // 更新file_id - spider.FileId = fid - if err := spider.Save(); err != nil { - log.Error("add spider error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 获取爬虫 - spider = model.GetSpiderByName(spiderName) - - // 发起同步 - services.PublishSpider(spider) - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: spider, - }) -} - -// @Summary Upload spider by id -// @Description Upload spider by id -// @Tags spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param file formData file true "spider file to upload" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /spiders/{id}/upload [post] -func UploadSpiderFromId(c *gin.Context) { - // TODO: 与 UploadSpider 部分逻辑重复,需要优化代码 - // 爬虫ID - spiderId := c.Param("id") - if !bson.IsObjectIdHex(spiderId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 获取爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(spiderId)) - if err != nil { - if err == mgo.ErrNotFound { - HandleErrorF(http.StatusNotFound, c, "cannot find spider") - } else { - HandleError(http.StatusInternalServerError, c, err) - } - return - } - - // 从body中获取文件 - uploadFile, err := c.FormFile("file") - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 如果不为zip文件,返回错误 - if !strings.HasSuffix(uploadFile.Filename, ".zip") { - debug.PrintStack() - HandleError(http.StatusBadRequest, c, errors.New("Not a valid zip file")) - return - } - - // 以防tmp目录不存在 - tmpPath := viper.GetString("other.tmppath") - if !utils.Exists(tmpPath) { - if err := os.MkdirAll(tmpPath, os.ModePerm); err != nil { - log.Error("mkdir other.tmppath dir error:" + err.Error()) - debug.PrintStack() - HandleError(http.StatusBadRequest, c, errors.New("Mkdir other.tmppath dir error")) - return - } - } - - // 保存到本地临时文件 - randomId := uuid.NewV4() - tmpFilePath := filepath.Join(tmpPath, randomId.String()+".zip") - if err := c.SaveUploadedFile(uploadFile, tmpFilePath); err != nil { - log.Error("save upload file error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取 GridFS 实例 - s, gf := database.GetGridFs("files") - defer s.Close() - - // 判断文件是否已经存在 - var gfFile model.GridFs - if err := gf.Find(bson.M{"filename": spider.Name}).One(&gfFile); err == nil { - // 已经存在文件,则删除 - if err := gf.RemoveId(gfFile.Id); err != nil { - log.Errorf("remove grid fs error: " + err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 上传到GridFs - fid, err := services.RetryUploadToGridFs(spider.Name, tmpFilePath) - if err != nil { - log.Errorf("upload to grid fs error: %s", err.Error()) - debug.PrintStack() - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 更新file_id - spider.FileId = fid - if err := spider.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - - // 发起同步 - services.PublishSpider(spider) - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Delete spider by id -// @Description Delete spider by id -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id} [delete] -func DeleteSpider(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - if err := services.RemoveSpider(id); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 更新 GitCron - if err := services.GitCron.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary delete spider -// @Description delete spider -// @Tags spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /spiders [post] -func DeleteSelectedSpider(c *gin.Context) { - type ReqBody struct { - SpiderIds []string `json:"spider_ids"` - } - - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - - for _, spiderId := range reqBody.SpiderIds { - if err := services.RemoveSpider(spiderId); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 更新 GitCron - if err := services.GitCron.Update(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary cancel spider -// @Description cancel spider -// @Tags spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /spiders-cancel [post] -func CancelSelectedSpider(c *gin.Context) { - type ReqBody struct { - SpiderIds []string `json:"spider_ids"` - } - - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - - for _, spiderId := range reqBody.SpiderIds { - if err := services.CancelSpider(spiderId); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary run spider -// @Description run spider -// @Tags spider -// @Accept json -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 500 json string Response -// @Router /spiders-run [post] -func RunSelectedSpider(c *gin.Context) { - type TaskParam struct { - SpiderId bson.ObjectId `json:"spider_id"` - Param string `json:"param"` - } - type ReqBody struct { - RunType string `json:"run_type"` - NodeIds []bson.ObjectId `json:"node_ids"` - TaskParams []TaskParam `json:"task_params"` - } - - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - - // 任务ID - var taskIds []string - - // 遍历爬虫 - // TODO: 优化此部分代码,与 routes.PutTask 有重合部分 - for _, taskParam := range reqBody.TaskParams { - if reqBody.RunType == constants.RunTypeAllNodes { - // 所有节点 - nodes, err := model.GetNodeList(nil) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - for _, node := range nodes { - t := model.Task{ - SpiderId: taskParam.SpiderId, - NodeId: node.Id, - Param: taskParam.Param, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeAllNodes, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSpider, - } - - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - taskIds = append(taskIds, id) - } - } else if reqBody.RunType == constants.RunTypeRandom { - // 随机 - t := model.Task{ - SpiderId: taskParam.SpiderId, - Param: taskParam.Param, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeRandom, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSpider, - } - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } else if reqBody.RunType == constants.RunTypeSelectedNodes { - // 指定节点 - for _, nodeId := range reqBody.NodeIds { - t := model.Task{ - SpiderId: taskParam.SpiderId, - NodeId: nodeId, - Param: taskParam.Param, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeSelectedNodes, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSpider, - } - - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } - } else { - HandleErrorF(http.StatusInternalServerError, c, "invalid run_type") - return - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: taskIds, - }) -} - -func SetProjectsSelectedSpider(c *gin.Context) { - type ReqBody struct { - ProjectId bson.ObjectId `json:"project_id"` - SpiderIds []bson.ObjectId `json:"spider_ids"` - } - - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - - for _, spiderId := range reqBody.SpiderIds { - spider, err := model.GetSpider(spiderId) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - spider.ProjectId = reqBody.ProjectId - if err := spider.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Get task list -// @Description Get task list -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/tasks [get] -func GetSpiderTasks(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - tasks, err := spider.GetTasks() - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: tasks, - }) -} - -// @Summary Get spider stats -// @Description Get spider stats -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/stats [get] -func GetSpiderStats(c *gin.Context) { - type Overview struct { - TaskCount int `json:"task_count" bson:"task_count"` - ResultCount int `json:"result_count" bson:"result_count"` - SuccessCount int `json:"success_count" bson:"success_count"` - SuccessRate float64 `json:"success_rate"` - TotalWaitDuration float64 `json:"wait_duration" bson:"wait_duration"` - TotalRuntimeDuration float64 `json:"runtime_duration" bson:"runtime_duration"` - AvgWaitDuration float64 `json:"avg_wait_duration"` - AvgRuntimeDuration float64 `json:"avg_runtime_duration"` - } - - type Data struct { - Overview Overview `json:"overview"` - Daily []model.TaskDailyItem `json:"daily"` - } - - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - log.Errorf(err.Error()) - HandleError(http.StatusInternalServerError, c, err) - return - } - - s, col := database.GetCol("tasks") - defer s.Close() - - // 起始日期 - startDate := time.Now().Add(-time.Hour * 24 * 30) - endDate := time.Now() - - // match - op1 := bson.M{ - "$match": bson.M{ - "spider_id": spider.Id, - "create_ts": bson.M{ - "$gte": startDate, - "$lt": endDate, - }, - }, - } - - // project - op2 := bson.M{ - "$project": bson.M{ - "success_count": bson.M{ - "$cond": []interface{}{ - bson.M{ - "$eq": []string{ - "$status", - constants.StatusFinished, - }, - }, - 1, - 0, - }, - }, - "result_count": "$result_count", - "wait_duration": "$wait_duration", - "runtime_duration": "$runtime_duration", - }, - } - - // group - op3 := bson.M{ - "$group": bson.M{ - "_id": nil, - "task_count": bson.M{"$sum": 1}, - "success_count": bson.M{"$sum": "$success_count"}, - "result_count": bson.M{"$sum": "$result_count"}, - "wait_duration": bson.M{"$sum": "$wait_duration"}, - "runtime_duration": bson.M{"$sum": "$runtime_duration"}, - }, - } - - // run aggregation pipeline - var overview Overview - if err := col.Pipe([]bson.M{op1, op2, op3}).One(&overview); err != nil { - if err == mgo.ErrNotFound { - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: Data{ - Overview: overview, - Daily: []model.TaskDailyItem{}, - }, - }) - return - } - log.Errorf(err.Error()) - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 后续处理 - successCount, _ := strconv.ParseFloat(strconv.Itoa(overview.SuccessCount), 64) - taskCount, _ := strconv.ParseFloat(strconv.Itoa(overview.TaskCount), 64) - overview.SuccessRate = successCount / taskCount - overview.AvgWaitDuration = overview.TotalWaitDuration / taskCount - overview.AvgRuntimeDuration = overview.TotalRuntimeDuration / taskCount - - items, err := model.GetDailyTaskStats(bson.M{"spider_id": spider.Id, "user_id": services.GetCurrentUserId(c)}) - if err != nil { - log.Errorf(err.Error()) - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: Data{ - Overview: overview, - Daily: items, - }, - }) -} - -// @Summary Get schedules -// @Description Get schedules -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/schedules [get] -func GetSpiderSchedules(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - // 获取定时任务 - list, err := model.GetScheduleList(bson.M{"spider_id": bson.ObjectIdHex(id)}) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: list, - }) -} - -// ======== ./爬虫管理 ======== - -// ======== 爬虫文件管理 ======== - -// @Summary Get spider dir -// @Description Get spider dir -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Param path query string true "path" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/dir [get] -func GetSpiderDir(c *gin.Context) { - // 爬虫ID - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 目录相对路径 - path := c.Query("path") - - // 获取爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取目录下文件列表 - spiderPath := viper.GetString("spider.path") - f, err := ioutil.ReadDir(filepath.Join(spiderPath, spider.Name, path)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 遍历文件列表 - var fileList []model.File - for _, file := range f { - fileList = append(fileList, model.File{ - Name: file.Name(), - IsDir: file.IsDir(), - Size: file.Size(), - Path: filepath.Join(path, file.Name()), - }) - } - - // 返回结果 - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: fileList, - }) -} - -type SpiderFileReqBody struct { - Path string `json:"path"` - Content string `json:"content"` - NewPath string `json:"new_path"` -} - -// @Summary Get spider file -// @Description Get spider file -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Param path query string true "path" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/file [get] -func GetSpiderFile(c *gin.Context) { - // 爬虫ID - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 文件相对路径 - path := c.Query("path") - - // 获取爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 读取文件 - fileBytes, err := ioutil.ReadFile(filepath.Join(spider.Src, path)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - } - - // 返回结果 - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: utils.BytesToString(fileBytes), - }) -} - -// @Summary Get spider dir -// @Description Get spider dir -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/file/tree [get] -func GetSpiderFileTree(c *gin.Context) { - // 爬虫ID - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 获取爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取目录下文件列表 - spiderPath := viper.GetString("spider.path") - spiderFilePath := filepath.Join(spiderPath, spider.Name) - - // 获取文件目录树 - fileNodeTree, err := services.GetFileNodeTree(spiderFilePath, 0) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 返回结果 - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: fileNodeTree, - }) -} - -// @Summary Post spider file -// @Description Post spider file -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Param reqBody body routes.SpiderFileReqBody true "path" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/file [post] -func PostSpiderFile(c *gin.Context) { - // 爬虫ID - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - // 文件相对路径 - var reqBody SpiderFileReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 获取爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 写文件 - if err := ioutil.WriteFile(filepath.Join(spider.Src, reqBody.Path), []byte(reqBody.Content), os.ModePerm); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 同步到GridFS - if err := services.UploadSpiderToGridFsFromMaster(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 返回结果 - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Put spider file -// @Description Put spider file -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Param reqBody body routes.SpiderFileReqBody true "path" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/file [post] -func PutSpiderFile(c *gin.Context) { - spiderId := c.Param("id") - if !bson.IsObjectIdHex(spiderId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var reqBody SpiderFileReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - spider, err := model.GetSpider(bson.ObjectIdHex(spiderId)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 文件路径 - filePath := path.Join(spider.Src, reqBody.Path) - - // 如果文件已存在,则报错 - if utils.Exists(filePath) { - HandleErrorF(http.StatusInternalServerError, c, fmt.Sprintf(`%s already exists`, filePath)) - return - } - - // 写入文件 - if err := ioutil.WriteFile(filePath, []byte(reqBody.Content), 0777); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 同步到GridFS - if err := services.UploadSpiderToGridFsFromMaster(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Post spider dir -// @Description Post spider dir -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Param reqBody body routes.SpiderFileReqBody true "path" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/file [put] -func PutSpiderDir(c *gin.Context) { - spiderId := c.Param("id") - if !bson.IsObjectIdHex(spiderId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var reqBody SpiderFileReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - spider, err := model.GetSpider(bson.ObjectIdHex(spiderId)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 文件路径 - filePath := path.Join(spider.Src, reqBody.Path) - - // 如果文件已存在,则报错 - if utils.Exists(filePath) { - HandleErrorF(http.StatusInternalServerError, c, fmt.Sprintf(`%s already exists`, filePath)) - return - } - - // 创建文件夹 - if err := os.MkdirAll(filePath, 0777); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 同步到GridFS - if err := services.UploadSpiderToGridFsFromMaster(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Delete spider file -// @Description Delete spider file -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Param reqBody body routes.SpiderFileReqBody true "path" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/file [delete] -func DeleteSpiderFile(c *gin.Context) { - spiderId := c.Param("id") - if !bson.IsObjectIdHex(spiderId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var reqBody SpiderFileReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - spider, err := model.GetSpider(bson.ObjectIdHex(spiderId)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - filePath := path.Join(spider.Src, reqBody.Path) - if err := os.RemoveAll(filePath); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 同步到GridFS - if err := services.UploadSpiderToGridFsFromMaster(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Rename spider file -// @Description Rename spider file -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Param reqBody body routes.SpiderFileReqBody true "path" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/file/rename [post] -func RenameSpiderFile(c *gin.Context) { - spiderId := c.Param("id") - - if !bson.IsObjectIdHex(spiderId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var reqBody SpiderFileReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - } - spider, err := model.GetSpider(bson.ObjectIdHex(spiderId)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 原文件路径 - filePath := path.Join(spider.Src, reqBody.Path) - newFilePath := path.Join(path.Join(path.Dir(filePath), reqBody.NewPath)) - - // 如果新文件已存在,则报错 - if utils.Exists(newFilePath) { - HandleErrorF(http.StatusInternalServerError, c, fmt.Sprintf(`%s already exists`, newFilePath)) - return - } - - // 重命名 - if err := os.Rename(filePath, newFilePath); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 删除原文件 - if err := os.RemoveAll(filePath); err != nil { - HandleError(http.StatusInternalServerError, c, err) - } - - // 同步到GridFS - if err := services.UploadSpiderToGridFsFromMaster(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// ======== 爬虫文件管理 ======== - -// ======== Scrapy 部分 ======== - -// @Summary Get scrapy spider file -// @Description Get scrapy spider file -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/scrapy/spiders [get] -func GetSpiderScrapySpiders(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - spiderNames, err := services.GetScrapySpiderNames(spider) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: spiderNames, - }) -} - -// @Summary Put scrapy spider file -// @Description Put scrapy spider file -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/scrapy/spiders [put] -func PutSpiderScrapySpiders(c *gin.Context) { - type ReqBody struct { - Name string `json:"name"` - Domain string `json:"domain"` - Template string `json:"template"` - } - - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - if err := services.CreateScrapySpider(spider, reqBody.Name, reqBody.Domain, reqBody.Template); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Get scrapy spider settings -// @Description Get scrapy spider settings -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/scrapy/settings [get] -func GetSpiderScrapySettings(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - data, err := services.GetScrapySettings(spider) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: data, - }) -} - -// @Summary Get scrapy spider file -// @Description Get scrapy spider file -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Param reqData body []entity.ScrapySettingParam true "req data" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/scrapy/settings [post] -func PostSpiderScrapySettings(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - var reqData []entity.ScrapySettingParam - if err := c.ShouldBindJSON(&reqData); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - if err := services.SaveScrapySettings(spider, reqData); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Get scrapy spider items -// @Description Get scrapy spider items -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/scrapy/items [get] -func GetSpiderScrapyItems(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - data, err := services.GetScrapyItems(spider) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: data, - }) -} - -// @Summary Post scrapy spider items -// @Description Post scrapy spider items -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Param reqData body []entity.ScrapyItem true "req data" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/scrapy/items [post] -func PostSpiderScrapyItems(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - var reqData []entity.ScrapyItem - if err := c.ShouldBindJSON(&reqData); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - if err := services.SaveScrapyItems(spider, reqData); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Get scrapy spider pipelines -// @Description Get scrapy spider pipelines -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/scrapy/pipelines [get] -func GetSpiderScrapyPipelines(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - data, err := services.GetScrapyPipelines(spider) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: data, - }) -} - -// @Summary Get scrapy spider file path -// @Description Get scrapy spider file path -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/scrapy/spider/filepath [get] -func GetSpiderScrapySpiderFilepath(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - spiderName := c.Query("spider_name") - if spiderName == "" { - HandleErrorF(http.StatusBadRequest, c, "spider_name is empty") - return - } - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - data, err := services.GetScrapySpiderFilepath(spider, spiderName) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: data, - }) -} - -// ======== ./Scrapy 部分 ======== - -// ======== Git 部分 ======== - -// @Summary Post spider sync git -// @Description Post spider sync git -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/git/sync [post] -func PostSpiderSyncGit(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - if err := services.SyncSpiderGit(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Post spider reset git -// @Description Post spider reset git -// @Tags spider -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "spider id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /spiders/{id}/git/reset [post] -func PostSpiderResetGit(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "spider_id is invalid") - return - } - - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - if err := services.ResetSpiderGit(spider); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// ======== ./Git 部分 ======== diff --git a/backend/routes/stats.go b/backend/routes/stats.go deleted file mode 100644 index 02e0993e..00000000 --- a/backend/routes/stats.go +++ /dev/null @@ -1,90 +0,0 @@ -package routes - -import ( - "crawlab/constants" - "crawlab/model" - "crawlab/services" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" -) - -// @Summary Get home stats -// @Description Get home stats -// @Tags version -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /stats/home [get] -func GetHomeStats(c *gin.Context) { - type DataOverview struct { - TaskCount int `json:"task_count"` - SpiderCount int `json:"spider_count"` - ActiveNodeCount int `json:"active_node_count"` - ScheduleCount int `json:"schedule_count"` - ProjectCount int `json:"project_count"` - } - - type Data struct { - Overview DataOverview `json:"overview"` - Daily []model.TaskDailyItem `json:"daily"` - } - - // 任务总数 - taskCount, err := model.GetTaskCount(bson.M{"user_id": services.GetCurrentUserId(c)}) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 在线节点总数 - activeNodeCount, err := model.GetNodeCount(bson.M{"status": constants.StatusOnline}) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 爬虫总数 - spiderCount, err := model.GetSpiderCount(bson.M{"user_id": services.GetCurrentUserId(c)}) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 定时任务数 - scheduleCount, err := model.GetScheduleCount(bson.M{"user_id": services.GetCurrentUserId(c)}) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 项目数 - projectCount, err := model.GetProjectCount(bson.M{"user_id": services.GetCurrentUserId(c)}) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 每日任务数 - items, err := model.GetDailyTaskStats(bson.M{"user_id": services.GetCurrentUserId(c)}) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: Data{ - Overview: DataOverview{ - ActiveNodeCount: activeNodeCount, - TaskCount: taskCount, - SpiderCount: spiderCount, - ScheduleCount: scheduleCount, - ProjectCount: projectCount, - }, - Daily: items, - }, - }) -} diff --git a/backend/routes/system.go b/backend/routes/system.go deleted file mode 100644 index a94be822..00000000 --- a/backend/routes/system.go +++ /dev/null @@ -1,344 +0,0 @@ -package routes - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/services" - "crawlab/services/rpc" - "fmt" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" - "strings" -) - -// @Summary Get language list -// @Description Get language list -// @Tags system -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "node id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id}/langs [get] -func GetLangList(c *gin.Context) { - nodeId := c.Param("id") - if !bson.IsObjectIdHex(nodeId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: services.GetLangList(nodeId), - }) -} - -// @Summary Get dep list -// @Description Get dep list -// @Tags system -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "node id" -// @Param lang query string true "language" -// @Param dep_name query string true "dep name" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id}/deps [get] -func GetDepList(c *gin.Context) { - nodeId := c.Param("id") - lang := c.Query("lang") - depName := c.Query("dep_name") - if !bson.IsObjectIdHex(nodeId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var depList []entity.Dependency - if lang == constants.Python { - list, err := services.GetPythonDepList(nodeId, depName) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - depList = list - } else if lang == constants.Nodejs { - list, err := services.GetNodejsDepList(nodeId, depName) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - depList = list - } else { - HandleErrorF(http.StatusBadRequest, c, fmt.Sprintf("%s is not implemented", lang)) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: depList, - }) -} - -// @Summary Get installed dep list -// @Description Get installed dep list -// @Tags system -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "node id" -// @Param lang query string true "language" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id}/deps/installed [get] -func GetInstalledDepList(c *gin.Context) { - nodeId := c.Param("id") - lang := c.Query("lang") - - if !bson.IsObjectIdHex(nodeId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var depList []entity.Dependency - if services.IsMasterNode(nodeId) { - list, err := rpc.GetInstalledDepsLocal(lang) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - depList = list - } else { - list, err := rpc.GetInstalledDepsRemote(nodeId, lang) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - depList = list - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: depList, - }) -} - -// @Summary Get all dep list -// @Description Get all dep list -// @Tags system -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param lang path string true "language" -// @Param dep_nane query string true "dep name" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /system/deps/:lang [get] -func GetAllDepList(c *gin.Context) { - lang := c.Param("lang") - depName := c.Query("dep_name") - - // 获取所有依赖列表 - var list []string - if lang == constants.Python { - _list, err := services.GetPythonDepListFromRedis() - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - list = _list - } else { - HandleErrorF(http.StatusBadRequest, c, fmt.Sprintf("%s is not implemented", lang)) - return - } - - // 过滤依赖列表 - var depList []string - for _, name := range list { - if strings.HasPrefix(strings.ToLower(name), strings.ToLower(depName)) { - depList = append(depList, name) - } - } - - // 只取前20 - var returnList []string - for i, name := range depList { - if i >= 10 { - break - } - returnList = append(returnList, name) - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: returnList, - }) -} - -// @Summary Install dep -// @Description Install dep -// @Tags system -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "node id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id}/deps/install [Post] -func InstallDep(c *gin.Context) { - type ReqBody struct { - Lang string `json:"lang"` - DepName string `json:"dep_name"` - } - - nodeId := c.Param("id") - if !bson.IsObjectIdHex(nodeId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - if services.IsMasterNode(nodeId) { - if err := rpc.InstallDepLocal(reqBody.Lang, reqBody.DepName); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } else { - if err := rpc.InstallDepRemote(nodeId, reqBody.Lang, reqBody.DepName); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Uninstall dep -// @Description Uninstall dep -// @Tags system -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "node id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id}/deps/uninstall [Post] -func UninstallDep(c *gin.Context) { - type ReqBody struct { - Lang string `json:"lang"` - DepName string `json:"dep_name"` - } - - nodeId := c.Param("id") - if !bson.IsObjectIdHex(nodeId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - } - - if services.IsMasterNode(nodeId) { - if err := rpc.UninstallDepLocal(reqBody.Lang, reqBody.DepName); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } else { - if err := rpc.UninstallDepRemote(nodeId, reqBody.Lang, reqBody.DepName); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Get dep json -// @Description Get dep json -// @Tags system -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param lang path string true "language" -// @Param dep_name path string true "dep name" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /system/deps/{lang}/{dep_name}/json [get] -func GetDepJson(c *gin.Context) { - depName := c.Param("dep_name") - lang := c.Param("lang") - - var dep entity.Dependency - if lang == constants.Python { - _dep, err := services.FetchPythonDepInfo(depName) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - dep = _dep - } else { - HandleErrorF(http.StatusBadRequest, c, fmt.Sprintf("%s is not implemented", lang)) - return - } - - c.Header("Cache-Control", "max-age=86400") - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: dep, - }) -} - -// @Summary Install language -// @Description Install language -// @Tags system -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "node id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /nodes/{id}/langs/install [Post] -func InstallLang(c *gin.Context) { - type ReqBody struct { - Lang string `json:"lang"` - } - - nodeId := c.Param("id") - if !bson.IsObjectIdHex(nodeId) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var reqBody ReqBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - if services.IsMasterNode(nodeId) { - _, err := rpc.InstallLangLocal(reqBody.Lang) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } else { - _, err := rpc.InstallLangRemote(nodeId, reqBody.Lang) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // TODO: check if install is successful - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/routes/system_tasks.go b/backend/routes/system_tasks.go deleted file mode 100644 index 087a2fb4..00000000 --- a/backend/routes/system_tasks.go +++ /dev/null @@ -1,118 +0,0 @@ -package routes - -import ( - "crawlab/constants" - "crawlab/model" - "crawlab/services" - "crawlab/utils" - "fmt" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" -) - -func GetSystemScripts(c *gin.Context) { - HandleSuccessData(c, utils.GetSystemScripts()) -} - -func PutSystemTask(c *gin.Context) { - type TaskRequestBody struct { - RunType string `json:"run_type"` - NodeIds []bson.ObjectId `json:"node_ids"` - Script string `json:"script"` - } - - // 绑定数据 - var reqBody TaskRequestBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 校验脚本参数不为空 - if reqBody.Script == "" { - HandleErrorF(http.StatusBadRequest, c, "script cannot be empty") - return - } - - // 校验脚本参数是否存在 - var allScripts = utils.GetSystemScripts() - if !utils.StringArrayContains(allScripts, reqBody.Script) { - HandleErrorF(http.StatusBadRequest, c, "script does not exist") - return - } - - // TODO: 校验脚本是否正在运行 - - // 获取执行命令 - cmd := fmt.Sprintf("sh %s", utils.GetSystemScriptPath(reqBody.Script)) - - // 任务ID - var taskIds []string - - if reqBody.RunType == constants.RunTypeAllNodes { - // 所有节点 - nodes, err := model.GetNodeList(nil) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - for _, node := range nodes { - t := model.Task{ - SpiderId: bson.ObjectIdHex(constants.ObjectIdNull), - NodeId: node.Id, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeAllNodes, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSystem, - Cmd: cmd, - } - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } - } else if reqBody.RunType == constants.RunTypeRandom { - // 随机 - t := model.Task{ - SpiderId: bson.ObjectIdHex(constants.ObjectIdNull), - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeRandom, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSystem, - Cmd: cmd, - } - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } else if reqBody.RunType == constants.RunTypeSelectedNodes { - // 指定节点 - for _, nodeId := range reqBody.NodeIds { - t := model.Task{ - SpiderId: bson.ObjectIdHex(constants.ObjectIdNull), - NodeId: nodeId, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeSelectedNodes, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSystem, - Cmd: cmd, - } - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } - } else { - HandleErrorF(http.StatusInternalServerError, c, "invalid run_type") - return - } - - HandleSuccessData(c, taskIds) -} diff --git a/backend/routes/task.go b/backend/routes/task.go deleted file mode 100644 index 2a74f4e8..00000000 --- a/backend/routes/task.go +++ /dev/null @@ -1,621 +0,0 @@ -package routes - -import ( - "bytes" - "crawlab/constants" - "crawlab/model" - "crawlab/services" - "crawlab/utils" - "encoding/csv" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" -) - -type TaskListRequestData struct { - PageNum int `form:"page_num"` - PageSize int `form:"page_size"` - NodeId string `form:"node_id"` - SpiderId string `form:"spider_id"` - ScheduleId string `form:"schedule_id"` - Status string `form:"status"` - Type string `form:"type"` -} - -type TaskResultsRequestData struct { - PageNum int `form:"page_num"` - PageSize int `form:"page_size"` -} - -// @Summary Get task list -// @Description Get task list -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param data body routes.TaskListRequestData true "req data" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks [get] -func GetTaskList(c *gin.Context) { - // 绑定数据 - data := TaskListRequestData{} - if err := c.ShouldBindQuery(&data); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - if data.PageNum == 0 { - data.PageNum = 1 - } - if data.PageSize == 0 { - data.PageSize = 10 - } - - // 过滤条件 - query := bson.M{} - if data.NodeId != "" { - query["node_id"] = bson.ObjectIdHex(data.NodeId) - } - if data.SpiderId != "" { - query["spider_id"] = bson.ObjectIdHex(data.SpiderId) - } - // 根据任务状态获取task列表 - if data.Status != "" { - query["status"] = data.Status - } - if data.ScheduleId != "" { - query["schedule_id"] = bson.ObjectIdHex(data.ScheduleId) - } - if data.Type != "" { - query["type"] = data.Type - } - - // 获取校验 - query = services.GetAuthQuery(query, c) - - // 获取任务列表 - tasks, err := model.GetTaskList(query, (data.PageNum-1)*data.PageSize, data.PageSize, "-create_ts") - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取总任务数 - total, err := model.GetTaskListTotal(query) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, ListResponse{ - Status: "ok", - Message: "success", - Total: total, - Data: tasks, - }) -} - -// @Summary Get task -// @Description Get task -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "task id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks/{id} [get] -func GetTask(c *gin.Context) { - id := c.Param("id") - result, err := model.GetTask(id) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccessData(c, result) -} - -// @Summary Put task -// @Description Put task -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks [put] -func PutTask(c *gin.Context) { - type TaskRequestBody struct { - SpiderId bson.ObjectId `json:"spider_id"` - RunType string `json:"run_type"` - NodeIds []bson.ObjectId `json:"node_ids"` - Param string `json:"param"` - } - - // 绑定数据 - var reqBody TaskRequestBody - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 任务ID - var taskIds []string - - if reqBody.RunType == constants.RunTypeAllNodes { - // 所有节点 - nodes, err := model.GetNodeList(nil) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - for _, node := range nodes { - t := model.Task{ - SpiderId: reqBody.SpiderId, - NodeId: node.Id, - Param: reqBody.Param, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeAllNodes, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSpider, - } - - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - taskIds = append(taskIds, id) - } - } else if reqBody.RunType == constants.RunTypeRandom { - // 随机 - t := model.Task{ - SpiderId: reqBody.SpiderId, - Param: reqBody.Param, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeRandom, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSpider, - } - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } else if reqBody.RunType == constants.RunTypeSelectedNodes { - // 指定节点 - for _, nodeId := range reqBody.NodeIds { - t := model.Task{ - SpiderId: reqBody.SpiderId, - NodeId: nodeId, - Param: reqBody.Param, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeSelectedNodes, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSpider, - } - - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } - } else { - HandleErrorF(http.StatusInternalServerError, c, "invalid run_type") - return - } - - HandleSuccessData(c, taskIds) -} - -func PutBatchTasks(c *gin.Context) { - var tasks []model.Task - if err := c.ShouldBindJSON(&tasks); err != nil { - HandleError(http.StatusOK, c, err) - return - } - var taskIds []string - for _, t := range tasks { - if t.RunType == constants.RunTypeAllNodes { - // 所有节点 - nodes, err := model.GetNodeList(nil) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - for _, node := range nodes { - t := model.Task{ - SpiderId: t.SpiderId, - NodeId: node.Id, - Param: t.Param, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeAllNodes, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSpider, - } - - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } - } else if t.RunType == constants.RunTypeRandom { - // 随机 - t := model.Task{ - SpiderId: t.SpiderId, - Param: t.Param, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeRandom, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSpider, - } - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } else if t.RunType == constants.RunTypeSelectedNodes { - // 指定节点 - for _, nodeId := range t.NodeIds { - t := model.Task{ - SpiderId: t.SpiderId, - NodeId: bson.ObjectIdHex(nodeId), - Param: t.Param, - UserId: services.GetCurrentUserId(c), - RunType: constants.RunTypeSelectedNodes, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: constants.TaskTypeSpider, - } - - id, err := services.AddTask(t) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - taskIds = append(taskIds, id) - } - } else { - HandleErrorF(http.StatusInternalServerError, c, "invalid run_type") - return - } - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: taskIds, - }) -} - -// @Summary Delete task -// @Description Delete task -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param status query string true "task status" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks_by_status [delete] -func DeleteTaskByStatus(c *gin.Context) { - status := c.Query("status") - - //删除相应的日志文件 - if err := services.RemoveLogByTaskStatus(status); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - //删除该状态下的task - if err := model.RemoveTaskByStatus(status); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - HandleSuccess(c) -} - -// 删除多个任务 - -// @Summary Delete tasks -// @Description Delete tasks -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks [delete] -func DeleteSelectedTask(c *gin.Context) { - ids := make(map[string][]string) - if err := c.ShouldBindJSON(&ids); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - list := ids["ids"] - for _, id := range list { - if err := services.RemoveLogByTaskId(id); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - if err := model.RemoveTask(id); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - HandleSuccess(c) -} - -// 删除单个任务 - -// @Summary Delete task -// @Description Delete task -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "task id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /task/{id} [delete] -func DeleteTask(c *gin.Context) { - id := c.Param("id") - // 删除日志文件 - if err := services.RemoveLogByTaskId(id); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - // 删除task - if err := model.RemoveTask(id); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccess(c) -} - -func CancelSelectedTask(c *gin.Context) { - ids := make(map[string][]string) - if err := c.ShouldBindJSON(&ids); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - list := ids["ids"] - for _, id := range list { - if err := services.CancelTask(id); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - HandleSuccess(c) -} - -func RestartSelectedTask(c *gin.Context) { - ids := make(map[string][]string) - if err := c.ShouldBindJSON(&ids); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - list := ids["ids"] - for _, id := range list { - if err := services.RestartTask(id, services.GetCurrentUserId(c)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - HandleSuccess(c) -} - -// @Summary Get task log -// @Description Get task log -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "task id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks/{id}/log [delete] -func GetTaskLog(c *gin.Context) { - type RequestData struct { - PageNum int `form:"page_num"` - PageSize int `form:"page_size"` - Keyword string `form:"keyword"` - } - id := c.Param("id") - var reqData RequestData - if err := c.ShouldBindQuery(&reqData); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - logItems, logTotal, err := services.GetTaskLog(id, reqData.Keyword, reqData.PageNum, reqData.PageSize) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, ListResponse{ - Status: "ok", - Message: "success", - Data: logItems, - Total: logTotal, - }) -} - -// @Summary Get task error log -// @Description Get task error log -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "task id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks/{id}/error-log [delete] -func GetTaskErrorLog(c *gin.Context) { - id := c.Param("id") - u := services.GetCurrentUser(c) - errLogItems, err := services.GetTaskErrorLog(id, u.Setting.MaxErrorLog) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: errLogItems, - }) -} - -// @Summary Get task list -// @Description Get task list -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param data body routes.TaskResultsRequestData true "req data" -// @Param id path string true "task id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks/{id}/results [get] -func GetTaskResults(c *gin.Context) { - id := c.Param("id") - // 绑定数据 - data := TaskResultsRequestData{} - if err := c.ShouldBindQuery(&data); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取任务 - task, err := model.GetTask(id) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取结果 - results, total, err := task.GetResults(data.PageNum, data.PageSize) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, ListResponse{ - Status: "ok", - Message: "success", - Data: results, - Total: total, - }) -} - -// @Summary Get task results -// @Description Get task results -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "task id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks/{id}/results/download [get] -func DownloadTaskResultsCsv(c *gin.Context) { - id := c.Param("id") - // 获取任务 - task, err := model.GetTask(id) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取结果 - results, _, err := task.GetResults(1, constants.Infinite) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 字段列表 - var columns []string - if len(results) == 0 { - columns = []string{} - } else { - item := results[0].(bson.M) - for key := range item { - columns = append(columns, key) - } - } - - // 缓冲 - bytesBuffer := &bytes.Buffer{} - - // 写入UTF-8 BOM,避免使用Microsoft Excel打开乱码 - bytesBuffer.WriteString("\xEF\xBB\xBF") - - writer := csv.NewWriter(bytesBuffer) - - // 写入表头 - if err := writer.Write(columns); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 写入内容 - for _, result := range results { - // 将result转换为[]string - item := result.(bson.M) - var values []string - for _, col := range columns { - value := utils.InterfaceToString(item[col]) - values = append(values, value) - } - - // 写入数据 - if err := writer.Write(values); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - } - - // 此时才会将缓冲区数据写入 - writer.Flush() - - // 设置下载的文件名 - c.Writer.Header().Set("Content-Disposition", "attachment;filename=data.csv") - - // 设置文件类型以及输出数据 - c.Data(http.StatusOK, "text/csv", bytesBuffer.Bytes()) -} - -// @Summary Cancel task -// @Description Cancel task -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "task id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks/{id}/cancel [post] -func CancelTask(c *gin.Context) { - id := c.Param("id") - if err := services.CancelTask(id); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccess(c) -} - -// @Summary Restart task -// @Description Restart task -// @Tags task -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "task id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tasks/{id}/restart [post] -func RestartTask(c *gin.Context) { - id := c.Param("id") - uid := services.GetCurrentUserId(c) - - if err := services.RestartTask(id, uid); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccess(c) -} diff --git a/backend/routes/token.go b/backend/routes/token.go deleted file mode 100644 index f62680a0..00000000 --- a/backend/routes/token.go +++ /dev/null @@ -1,96 +0,0 @@ -package routes - -import ( - "crawlab/model" - "crawlab/services" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" - "time" -) - -// @Summary Get token -// @Description token -// @Tags token -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tokens [get] -func GetTokens(c *gin.Context) { - u := services.GetCurrentUser(c) - - tokens, err := model.GetTokensByUserId(u.Id) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: tokens, - }) -} - -// @Summary Put token -// @Description token -// @Tags token -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tokens [put] -func PutToken(c *gin.Context) { - u := services.GetCurrentUser(c) - - tokenStr, err := services.MakeToken(u) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - t := model.Token{ - Id: bson.NewObjectId(), - Token: tokenStr, - UserId: u.Id, - CreateTs: time.Now(), - UpdateTs: time.Now(), - } - - if err := t.Add(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Delete token -// @Description Delete token -// @Tags token -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "token id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /tokens/{id} [delete] -func DeleteToken(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - if err := model.DeleteTokenById(bson.ObjectIdHex(id)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/routes/user.go b/backend/routes/user.go deleted file mode 100644 index abb77170..00000000 --- a/backend/routes/user.go +++ /dev/null @@ -1,340 +0,0 @@ -package routes - -import ( - "crawlab/constants" - "crawlab/model" - "crawlab/services" - "crawlab/services/context" - "crawlab/utils" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "github.com/pkg/errors" - "net/http" - "strings" -) - -type UserListRequestData struct { - PageNum int `form:"page_num"` - PageSize int `form:"page_size"` -} - -type UserRequestData struct { - Username string `json:"username"` - Password string `json:"password"` - Role string `json:"role"` - Email string `json:"email"` -} - -// @Summary Get user -// @Description user -// @Tags user -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "user id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /users/{id} [get] -func GetUser(c *gin.Context) { - id := c.Param("id") - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - user, err := model.GetUser(bson.ObjectIdHex(id)) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: user, - }) -} - -// @Summary Get user list -// @Description Get user list -// @Tags token -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param data body routes.UserListRequestData true "data body" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /users [get] -func GetUserList(c *gin.Context) { - // 绑定数据 - data := UserListRequestData{} - if err := c.ShouldBindQuery(&data); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - if data.PageNum == 0 { - data.PageNum = 1 - } - if data.PageSize == 0 { - data.PageNum = 10 - } - - // 获取用户列表 - users, err := model.GetUserList(nil, (data.PageNum-1)*data.PageSize, data.PageSize, "-create_ts") - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 获取总用户数 - total, err := model.GetUserListTotal(nil) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - // 去除密码 - for i := range users { - users[i].Password = "" - } - - c.JSON(http.StatusOK, ListResponse{ - Status: "ok", - Message: "success", - Data: users, - Total: total, - }) -} - -// @Summary Put user -// @Description Put user -// @Tags user -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param reqData body routes.UserRequestData true "reqData body" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /users [put] -func PutUser(c *gin.Context) { - // 绑定请求数据 - var reqData UserRequestData - if err := c.ShouldBindJSON(&reqData); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - // 默认为正常用户 - if reqData.Role == "" { - reqData.Role = constants.RoleNormal - } - - // UserId - uid := services.GetCurrentUserId(c) - - // 空 UserId 处理 - if uid == "" { - uid = bson.ObjectIdHex(constants.ObjectIdNull) - } - - // 添加用户 - if err := services.CreateNewUser(reqData.Username, reqData.Password, reqData.Role, reqData.Email, uid); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Post user -// @Description Post user -// @Tags user -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param item body model.User true "user body" -// @Param id path string true "user id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /users/{id} [post] -func PostUser(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - var item model.User - if err := c.ShouldBindJSON(&item); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - - if item.UserId.Hex() == "" { - item.UserId = bson.ObjectIdHex(constants.ObjectIdNull) - } - - if err := model.UpdateUser(bson.ObjectIdHex(id), item); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -// @Summary Delete user -// @Description Delete user -// @Tags user -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "user id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /users/{id} [delete] -func DeleteUser(c *gin.Context) { - id := c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - - // 从数据库中删除该爬虫 - if err := model.RemoveUser(bson.ObjectIdHex(id)); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func Login(c *gin.Context) { - // 绑定请求数据 - var reqData UserRequestData - if err := c.ShouldBindJSON(&reqData); err != nil { - HandleError(http.StatusUnauthorized, c, errors.New("not authorized")) - return - } - - // 获取用户 - user, err := model.GetUserByUsername(strings.ToLower(reqData.Username)) - if err != nil { - HandleError(http.StatusUnauthorized, c, errors.New("not authorized")) - return - } - - // 校验密码 - encPassword := utils.EncryptPassword(reqData.Password) - if user.Password != encPassword { - HandleError(http.StatusUnauthorized, c, errors.New("not authorized")) - return - } - - // 获取token - tokenStr, err := services.MakeToken(&user) - if err != nil { - HandleError(http.StatusUnauthorized, c, errors.New("not authorized")) - return - } - - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: tokenStr, - }) -} - -func GetMe(c *gin.Context) { - ctx := context.WithGinContext(c) - user := ctx.User() - if user == nil { - ctx.FailedWithError(constants.ErrorUserNotFound, http.StatusUnauthorized) - return - } - ctx.Success(struct { - *model.User - Password string `json:"password,omitempty"` - }{ - User: user, - }, nil) -} - -func PostMe(c *gin.Context) { - ctx := context.WithGinContext(c) - user := ctx.User() - if user == nil { - ctx.FailedWithError(constants.ErrorUserNotFound, http.StatusUnauthorized) - return - } - var reqBody model.User - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - if reqBody.Email != "" { - user.Email = reqBody.Email - } - if reqBody.Setting.NotificationTrigger != "" { - user.Setting.NotificationTrigger = reqBody.Setting.NotificationTrigger - } - if reqBody.Setting.DingTalkRobotWebhook != "" { - user.Setting.DingTalkRobotWebhook = reqBody.Setting.DingTalkRobotWebhook - } - if reqBody.Setting.WechatRobotWebhook != "" { - user.Setting.WechatRobotWebhook = reqBody.Setting.WechatRobotWebhook - } - user.Setting.EnabledNotifications = reqBody.Setting.EnabledNotifications - user.Setting.ErrorRegexPattern = reqBody.Setting.ErrorRegexPattern - if reqBody.Setting.MaxErrorLog != 0 { - user.Setting.MaxErrorLog = reqBody.Setting.MaxErrorLog - } - user.Setting.LogExpireDuration = reqBody.Setting.LogExpireDuration - - if user.UserId.Hex() == "" { - user.UserId = bson.ObjectIdHex(constants.ObjectIdNull) - } - - if err := user.Save(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func PostMeChangePassword(c *gin.Context) { - ctx := context.WithGinContext(c) - user := ctx.User() - if user == nil { - ctx.FailedWithError(constants.ErrorUserNotFound, http.StatusUnauthorized) - return - } - var reqBody model.User - if err := c.ShouldBindJSON(&reqBody); err != nil { - HandleErrorF(http.StatusBadRequest, c, "invalid request") - return - } - if reqBody.Password == "" { - HandleErrorF(http.StatusBadRequest, c, "password is empty") - return - } - if user.UserId.Hex() == "" { - user.UserId = bson.ObjectIdHex(constants.ObjectIdNull) - } - user.Password = utils.EncryptPassword(reqBody.Password) - if err := user.Save(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} diff --git a/backend/routes/utils.go b/backend/routes/utils.go deleted file mode 100644 index dfa5420e..00000000 --- a/backend/routes/utils.go +++ /dev/null @@ -1,39 +0,0 @@ -package routes - -import ( - "github.com/gin-gonic/gin" - "net/http" - "runtime/debug" -) - -func HandleError(statusCode int, c *gin.Context, err error) { - c.AbortWithStatusJSON(statusCode, Response{ - Status: "error", - Message: "failure", - Error: err.Error(), - }) -} - -func HandleErrorF(statusCode int, c *gin.Context, err string) { - debug.PrintStack() - c.AbortWithStatusJSON(statusCode, Response{ - Status: "ok", - Message: "error", - Error: err, - }) -} - -func HandleSuccess(c *gin.Context) { - c.AbortWithStatusJSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - }) -} - -func HandleSuccessData(c *gin.Context, data interface{}) { - c.AbortWithStatusJSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: data, - }) -} diff --git a/backend/routes/variable.go b/backend/routes/variable.go deleted file mode 100644 index 8b837538..00000000 --- a/backend/routes/variable.go +++ /dev/null @@ -1,111 +0,0 @@ -package routes - -import ( - "crawlab/model" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "net/http" -) - -// 新增 - -// @Summary Put variable -// @Description Put variable -// @Tags variable -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param variable body model.Variable true "reqData body" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /variable [put] -func PutVariable(c *gin.Context) { - var variable model.Variable - if err := c.ShouldBindJSON(&variable); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - if err := variable.Add(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccess(c) -} - -// 修改 - -// @Summary Post variable -// @Description Post variable -// @Tags variable -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param variable body model.Variable true "reqData body" -// @Param id path string true "variable id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /variable/{id} [post] -func PostVariable(c *gin.Context) { - var id = c.Param("id") - - if !bson.IsObjectIdHex(id) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var variable model.Variable - if err := c.ShouldBindJSON(&variable); err != nil { - HandleError(http.StatusBadRequest, c, err) - return - } - variable.Id = bson.ObjectIdHex(id) - if err := variable.Save(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccess(c) -} - -// 删除 - -// @Summary Delete variable -// @Description Delete variable -// @Tags variable -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Param id path string true "variable id" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /variable/{id} [delete] -func DeleteVariable(c *gin.Context) { - var idStr = c.Param("id") - if !bson.IsObjectIdHex(idStr) { - HandleErrorF(http.StatusBadRequest, c, "invalid id") - return - } - var id = bson.ObjectIdHex(idStr) - variable, err := model.GetVariable(id) - if err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - variable.Id = id - if err := variable.Delete(); err != nil { - HandleError(http.StatusInternalServerError, c, err) - return - } - HandleSuccess(c) - -} - -// 列表 - -// @Summary Get variable list -// @Description Get variable list -// @Tags variable -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /variables [get] -func GetVariableList(c *gin.Context) { - list := model.GetVariableList() - HandleSuccessData(c, list) -} diff --git a/backend/routes/version.go b/backend/routes/version.go deleted file mode 100644 index 8974e7fa..00000000 --- a/backend/routes/version.go +++ /dev/null @@ -1,30 +0,0 @@ -package routes - -import ( - "crawlab/services" - "github.com/apex/log" - "github.com/gin-gonic/gin" - "net/http" - "runtime/debug" -) - -// @Summary Get latest release -// @Description Get latest release -// @Tags version -// @Produce json -// @Param Authorization header string true "Authorization token" -// @Success 200 json string Response -// @Failure 400 json string Response -// @Router /releases/latest [get] -func GetLatestRelease(c *gin.Context) { - latestRelease, err := services.GetLatestRelease() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - } - c.JSON(http.StatusOK, Response{ - Status: "ok", - Message: "success", - Data: latestRelease, - }) -} diff --git a/backend/scripts/install-chromedriver.sh b/backend/scripts/install-chromedriver.sh deleted file mode 100644 index c2e86939..00000000 --- a/backend/scripts/install-chromedriver.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# fail immediately if error -set -e - -# lock global -touch /tmp/install.lock - -# lock -touch /tmp/install-chromedriver.lock - -export DEBIAN_FRONTEND=noninteractive -apt-get update -apt-get install unzip -DL=https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -curl -sL "$DL" > /tmp/chrome.deb -apt install --no-install-recommends --no-install-suggests -y /tmp/chrome.deb -CHROMIUM_FLAGS='--no-sandbox --disable-dev-shm-usage' -sed -i '${s/$/'" $CHROMIUM_FLAGS"'/}' /opt/google/chrome/google-chrome -BASE_URL=https://chromedriver.storage.googleapis.com -VERSION=$(curl -sL "$BASE_URL/LATEST_RELEASE") -curl -sL "$BASE_URL/$VERSION/chromedriver_linux64.zip" -o /tmp/driver.zip -unzip /tmp/driver.zip -chmod 755 chromedriver -mv chromedriver /usr/local/bin - -# unlock global -rm /tmp/install.lock - -# unlock -rm /tmp/install-chromedriver.lock \ No newline at end of file diff --git a/backend/scripts/install-dotnet.sh b/backend/scripts/install-dotnet.sh deleted file mode 100755 index 73f3d0cb..00000000 --- a/backend/scripts/install-dotnet.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -# fail immediately if error -set -e - -# lock global -touch /tmp/install.lock - -# lock -touch /tmp/install-dotnet.lock - -wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb -dpkg -i packages-microsoft-prod.deb -apt-get install -y apt-transport-https -apt-get update -apt-get install -y dotnet-sdk-2.1 dotnet-runtime-2.1 aspnetcore-runtime-2.1 - -# unlock global -rm /tmp/install.lock - -# unlock -rm /tmp/install-dotnet.lock diff --git a/backend/scripts/install-firefox.sh b/backend/scripts/install-firefox.sh deleted file mode 100644 index f316b3db..00000000 --- a/backend/scripts/install-firefox.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# fail immediately if error -set -e - -# lock global -touch /tmp/install.lock - -# lock -touch /tmp/install-firefox.lock - -apt-get update -apt-get -y install firefox ttf-wqy-microhei ttf-wqy-zenhei xfonts-wqy -apt-get -y install libcanberra-gtk3-module - -# unlock global -rm /tmp/install.lock - -# unlock -rm /tmp/install-firefox.lock \ No newline at end of file diff --git a/backend/scripts/install-go.sh b/backend/scripts/install-go.sh deleted file mode 100644 index 44d43744..00000000 --- a/backend/scripts/install-go.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# fail immediately if error -set -e - -# lock global -touch /tmp/install.lock - -# lock -touch /tmp/install-go.lock - -# install golang -apt-get update -apt-get install -y golang - -# environment variables -export GOPROXY=https://goproxy.cn -export GOPATH=/opt/go - -# unlock global -rm /tmp/install.lock - -# unlock -rm /tmp/install-go.lock \ No newline at end of file diff --git a/backend/scripts/install-java.sh b/backend/scripts/install-java.sh deleted file mode 100755 index ab797cb9..00000000 --- a/backend/scripts/install-java.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -# fail immediately if error -set -e - -# lock global -touch /tmp/install.lock - -# lock -touch /tmp/install-java.lock - -# install java -apt-get clean -apt-get update --fix-missing -apt-get install -y --fix-missing default-jdk -ln -s /usr/bin/java /usr/local/bin/java - -# unlock -rm /tmp/install-java.lock - -# unlock global -rm /tmp/install.lock diff --git a/backend/scripts/install-nodejs.sh b/backend/scripts/install-nodejs.sh deleted file mode 100644 index 61b4d778..00000000 --- a/backend/scripts/install-nodejs.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# fail immediately if error -set -e - -# lock global -touch /tmp/install.lock - -# lock -touch /tmp/install-nodejs.lock - -# install node.js -curl -sL https://deb.nodesource.com/setup_12.x | bash - -apt-get update && apt install -y nodejs - -# install chromium -# See https://crbug.com/795759 -apt-get update && apt-get install -yq libgconf-2-4 - -# Install latest chrome dev package and fonts to support major -# charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others) -# Note: this installs the necessary libs to make the bundled version -# of Chromium that Puppeteer -# installs, work. -apt-get update \ - && apt-get install -y wget gnupg \ - && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ - && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ - && apt-get update \ - && apt-get -y install xvfb gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 \ - libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 \ - libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 \ - libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 \ - libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget \ - && rm -rf /var/lib/apt/lists/* - -# install default dependencies -PUPPETEER_DOWNLOAD_HOST=https://npm.taobao.org/mirrors -npm config set puppeteer_download_host=https://npm.taobao.org/mirrors -npm install puppeteer-chromium-resolver crawlab-sdk -g --unsafe-perm=true --registry=https://registry.npm.taobao.org - -# unlock -rm /tmp/install-nodejs.lock - -# unlock global -rm /tmp/install.lock diff --git a/backend/scripts/install-nvm.sh b/backend/scripts/install-nvm.sh deleted file mode 100755 index d02f884c..00000000 --- a/backend/scripts/install-nvm.sh +++ /dev/null @@ -1,428 +0,0 @@ -#!/bin/bash - -# fail immediately if error -set -e - -{ # this ensures the entire script is downloaded # - -nvm_has() { - type "$1" > /dev/null 2>&1 -} - -nvm_default_install_dir() { - [ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm" -} - -nvm_install_dir() { - if [ -n "$NVM_DIR" ]; then - printf %s "${NVM_DIR}" - else - nvm_default_install_dir - fi -} - -nvm_latest_version() { - echo "v0.35.2" -} - -nvm_profile_is_bash_or_zsh() { - local TEST_PROFILE - TEST_PROFILE="${1-}" - case "${TEST_PROFILE-}" in - *"/.bashrc" | *"/.bash_profile" | *"/.zshrc") - return - ;; - *) - return 1 - ;; - esac -} - -# -# Outputs the location to NVM depending on: -# * The availability of $NVM_SOURCE -# * The method used ("script" or "git" in the script, defaults to "git") -# NVM_SOURCE always takes precedence unless the method is "script-nvm-exec" -# -nvm_source() { - local NVM_METHOD - NVM_METHOD="$1" - local NVM_SOURCE_URL - NVM_SOURCE_URL="$NVM_SOURCE" - if [ "_$NVM_METHOD" = "_script-nvm-exec" ]; then - NVM_SOURCE_URL="https://raw.githubusercontent.com/nvm-sh/nvm/$(nvm_latest_version)/nvm-exec" - elif [ "_$NVM_METHOD" = "_script-nvm-bash-completion" ]; then - NVM_SOURCE_URL="https://raw.githubusercontent.com/nvm-sh/nvm/$(nvm_latest_version)/bash_completion" - elif [ -z "$NVM_SOURCE_URL" ]; then - if [ "_$NVM_METHOD" = "_script" ]; then - NVM_SOURCE_URL="https://raw.githubusercontent.com/nvm-sh/nvm/$(nvm_latest_version)/nvm.sh" - elif [ "_$NVM_METHOD" = "_git" ] || [ -z "$NVM_METHOD" ]; then - NVM_SOURCE_URL="https://github.com/nvm-sh/nvm.git" - else - echo >&2 "Unexpected value \"$NVM_METHOD\" for \$NVM_METHOD" - return 1 - fi - fi - echo "$NVM_SOURCE_URL" -} - -# -# Node.js version to install -# -nvm_node_version() { - echo "$NODE_VERSION" -} - -nvm_download() { - if nvm_has "curl"; then - curl --compressed -q "$@" - elif nvm_has "wget"; then - # Emulate curl with wget - ARGS=$(echo "$*" | command sed -e 's/--progress-bar /--progress=bar /' \ - -e 's/-L //' \ - -e 's/--compressed //' \ - -e 's/-I /--server-response /' \ - -e 's/-s /-q /' \ - -e 's/-o /-O /' \ - -e 's/-C - /-c /') - # shellcheck disable=SC2086 - eval wget $ARGS - fi -} - -install_nvm_from_git() { - local INSTALL_DIR - INSTALL_DIR="$(nvm_install_dir)" - - if [ -d "$INSTALL_DIR/.git" ]; then - echo "=> nvm is already installed in $INSTALL_DIR, trying to update using git" - command printf '\r=> ' - command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" fetch origin tag "$(nvm_latest_version)" --depth=1 2> /dev/null || { - echo >&2 "Failed to update nvm, run 'git fetch' in $INSTALL_DIR yourself." - exit 1 - } - else - # Cloning to $INSTALL_DIR - echo "=> Downloading nvm from git to '$INSTALL_DIR'" - command printf '\r=> ' - mkdir -p "${INSTALL_DIR}" - if [ "$(ls -A "${INSTALL_DIR}")" ]; then - command git init "${INSTALL_DIR}" || { - echo >&2 'Failed to initialize nvm repo. Please report this!' - exit 2 - } - command git --git-dir="${INSTALL_DIR}/.git" remote add origin "$(nvm_source)" 2> /dev/null \ - || command git --git-dir="${INSTALL_DIR}/.git" remote set-url origin "$(nvm_source)" || { - echo >&2 'Failed to add remote "origin" (or set the URL). Please report this!' - exit 2 - } - command git --git-dir="${INSTALL_DIR}/.git" fetch origin tag "$(nvm_latest_version)" --depth=1 || { - echo >&2 'Failed to fetch origin with tags. Please report this!' - exit 2 - } - else - command git -c advice.detachedHead=false clone "$(nvm_source)" -b "$(nvm_latest_version)" --depth=1 "${INSTALL_DIR}" || { - echo >&2 'Failed to clone nvm repo. Please report this!' - exit 2 - } - fi - fi - command git -c advice.detachedHead=false --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" checkout -f --quiet "$(nvm_latest_version)" - if [ -n "$(command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" show-ref refs/heads/master)" ]; then - if command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" branch --quiet 2>/dev/null; then - command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" branch --quiet -D master >/dev/null 2>&1 - else - echo >&2 "Your version of git is out of date. Please update it!" - command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" branch -D master >/dev/null 2>&1 - fi - fi - - echo "=> Compressing and cleaning up git repository" - if ! command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" reflog expire --expire=now --all; then - echo >&2 "Your version of git is out of date. Please update it!" - fi - if ! command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" gc --auto --aggressive --prune=now ; then - echo >&2 "Your version of git is out of date. Please update it!" - fi - return -} - -# -# Automatically install Node.js -# -nvm_install_node() { - local NODE_VERSION_LOCAL - NODE_VERSION_LOCAL="$(nvm_node_version)" - - if [ -z "$NODE_VERSION_LOCAL" ]; then - return 0 - fi - - echo "=> Installing Node.js version $NODE_VERSION_LOCAL" - nvm install "$NODE_VERSION_LOCAL" - local CURRENT_NVM_NODE - - CURRENT_NVM_NODE="$(nvm_version current)" - if [ "$(nvm_version "$NODE_VERSION_LOCAL")" == "$CURRENT_NVM_NODE" ]; then - echo "=> Node.js version $NODE_VERSION_LOCAL has been successfully installed" - else - echo >&2 "Failed to install Node.js $NODE_VERSION_LOCAL" - fi -} - -install_nvm_as_script() { - local INSTALL_DIR - INSTALL_DIR="$(nvm_install_dir)" - local NVM_SOURCE_LOCAL - NVM_SOURCE_LOCAL="$(nvm_source script)" - local NVM_EXEC_SOURCE - NVM_EXEC_SOURCE="$(nvm_source script-nvm-exec)" - local NVM_BASH_COMPLETION_SOURCE - NVM_BASH_COMPLETION_SOURCE="$(nvm_source script-nvm-bash-completion)" - - # Downloading to $INSTALL_DIR - mkdir -p "$INSTALL_DIR" - if [ -f "$INSTALL_DIR/nvm.sh" ]; then - echo "=> nvm is already installed in $INSTALL_DIR, trying to update the script" - else - echo "=> Downloading nvm as script to '$INSTALL_DIR'" - fi - nvm_download -s "$NVM_SOURCE_LOCAL" -o "$INSTALL_DIR/nvm.sh" || { - echo >&2 "Failed to download '$NVM_SOURCE_LOCAL'" - return 1 - } & - nvm_download -s "$NVM_EXEC_SOURCE" -o "$INSTALL_DIR/nvm-exec" || { - echo >&2 "Failed to download '$NVM_EXEC_SOURCE'" - return 2 - } & - nvm_download -s "$NVM_BASH_COMPLETION_SOURCE" -o "$INSTALL_DIR/bash_completion" || { - echo >&2 "Failed to download '$NVM_BASH_COMPLETION_SOURCE'" - return 2 - } & - for job in $(jobs -p | command sort) - do - wait "$job" || return $? - done - chmod a+x "$INSTALL_DIR/nvm-exec" || { - echo >&2 "Failed to mark '$INSTALL_DIR/nvm-exec' as executable" - return 3 - } -} - -nvm_try_profile() { - if [ -z "${1-}" ] || [ ! -f "${1}" ]; then - return 1 - fi - echo "${1}" -} - -# -# Detect profile file if not specified as environment variable -# (eg: PROFILE=~/.myprofile) -# The echo'ed path is guaranteed to be an existing file -# Otherwise, an empty string is returned -# -nvm_detect_profile() { - if [ "${PROFILE-}" = '/dev/null' ]; then - # the user has specifically requested NOT to have nvm touch their profile - return - fi - - if [ -n "${PROFILE}" ] && [ -f "${PROFILE}" ]; then - echo "${PROFILE}" - return - fi - - local DETECTED_PROFILE - DETECTED_PROFILE='' - - if [ -n "${BASH_VERSION-}" ]; then - if [ -f "$HOME/.bashrc" ]; then - DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then - DETECTED_PROFILE="$HOME/.bash_profile" - fi - elif [ -n "${ZSH_VERSION-}" ]; then - DETECTED_PROFILE="$HOME/.zshrc" - fi - - if [ -z "$DETECTED_PROFILE" ]; then - for EACH_PROFILE in ".profile" ".bashrc" ".bash_profile" ".zshrc" - do - if DETECTED_PROFILE="$(nvm_try_profile "${HOME}/${EACH_PROFILE}")"; then - break - fi - done - fi - - if [ -n "$DETECTED_PROFILE" ]; then - echo "$DETECTED_PROFILE" - fi -} - -# -# Check whether the user has any globally-installed npm modules in their system -# Node, and warn them if so. -# -nvm_check_global_modules() { - command -v npm >/dev/null 2>&1 || return 0 - - local NPM_VERSION - NPM_VERSION="$(npm --version)" - NPM_VERSION="${NPM_VERSION:--1}" - [ "${NPM_VERSION%%[!-0-9]*}" -gt 0 ] || return 0 - - local NPM_GLOBAL_MODULES - NPM_GLOBAL_MODULES="$( - npm list -g --depth=0 | - command sed -e '/ npm@/d' -e '/ (empty)$/d' - )" - - local MODULE_COUNT - MODULE_COUNT="$( - command printf %s\\n "$NPM_GLOBAL_MODULES" | - command sed -ne '1!p' | # Remove the first line - wc -l | command tr -d ' ' # Count entries - )" - - if [ "${MODULE_COUNT}" != '0' ]; then - # shellcheck disable=SC2016 - echo '=> You currently have modules installed globally with `npm`. These will no' - # shellcheck disable=SC2016 - echo '=> longer be linked to the active version of Node when you install a new node' - # shellcheck disable=SC2016 - echo '=> with `nvm`; and they may (depending on how you construct your `$PATH`)' - # shellcheck disable=SC2016 - echo '=> override the binaries of modules installed with `nvm`:' - echo - - command printf %s\\n "$NPM_GLOBAL_MODULES" - echo '=> If you wish to uninstall them at a later point (or re-install them under your' - # shellcheck disable=SC2016 - echo '=> `nvm` Nodes), you can remove them from the system Node as follows:' - echo - echo ' $ nvm use system' - echo ' $ npm uninstall -g a_module' - echo - fi -} - -nvm_do_install() { - if [ -n "${NVM_DIR-}" ] && ! [ -d "${NVM_DIR}" ]; then - if [ -e "${NVM_DIR}" ]; then - echo >&2 "File \"${NVM_DIR}\" has the same name as installation directory." - exit 1 - fi - - if [ "${NVM_DIR}" = "$(nvm_default_install_dir)" ]; then - mkdir "${NVM_DIR}" - else - echo >&2 "You have \$NVM_DIR set to \"${NVM_DIR}\", but that directory does not exist. Check your profile files and environment." - exit 1 - fi - fi - if [ -z "${METHOD}" ]; then - # Autodetect install method - if nvm_has git; then - install_nvm_from_git - elif nvm_has nvm_download; then - install_nvm_as_script - else - echo >&2 'You need git, curl, or wget to install nvm' - exit 1 - fi - elif [ "${METHOD}" = 'git' ]; then - if ! nvm_has git; then - echo >&2 "You need git to install nvm" - exit 1 - fi - install_nvm_from_git - elif [ "${METHOD}" = 'script' ]; then - if ! nvm_has nvm_download; then - echo >&2 "You need curl or wget to install nvm" - exit 1 - fi - install_nvm_as_script - else - echo >&2 "The environment variable \$METHOD is set to \"${METHOD}\", which is not recognized as a valid installation method." - exit 1 - fi - - echo - - local NVM_PROFILE - NVM_PROFILE="$(nvm_detect_profile)" - local PROFILE_INSTALL_DIR - PROFILE_INSTALL_DIR="$(nvm_install_dir | command sed "s:^$HOME:\$HOME:")" - - SOURCE_STR="\\nexport NVM_DIR=\"${PROFILE_INSTALL_DIR}\"\\n[ -s \"\$NVM_DIR/nvm.sh\" ] && \\. \"\$NVM_DIR/nvm.sh\" # This loads nvm\\n" - - # shellcheck disable=SC2016 - COMPLETION_STR='[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion\n' - BASH_OR_ZSH=false - - if [ -z "${NVM_PROFILE-}" ] ; then - local TRIED_PROFILE - if [ -n "${PROFILE}" ]; then - TRIED_PROFILE="${NVM_PROFILE} (as defined in \$PROFILE), " - fi - echo "=> Profile not found. Tried ${TRIED_PROFILE-}~/.bashrc, ~/.bash_profile, ~/.zshrc, and ~/.profile." - echo "=> Create one of them and run this script again" - echo " OR" - echo "=> Append the following lines to the correct file yourself:" - command printf "${SOURCE_STR}" - echo - else - if nvm_profile_is_bash_or_zsh "${NVM_PROFILE-}"; then - BASH_OR_ZSH=true - fi - if ! command grep -qc '/nvm.sh' "$NVM_PROFILE"; then - echo "=> Appending nvm source string to $NVM_PROFILE" - command printf "${SOURCE_STR}" >> "$NVM_PROFILE" - else - echo "=> nvm source string already in ${NVM_PROFILE}" - fi - # shellcheck disable=SC2016 - if ${BASH_OR_ZSH} && ! command grep -qc '$NVM_DIR/bash_completion' "$NVM_PROFILE"; then - echo "=> Appending bash_completion source string to $NVM_PROFILE" - command printf "$COMPLETION_STR" >> "$NVM_PROFILE" - else - echo "=> bash_completion source string already in ${NVM_PROFILE}" - fi - fi - if ${BASH_OR_ZSH} && [ -z "${NVM_PROFILE-}" ] ; then - echo "=> Please also append the following lines to the if you are using bash/zsh shell:" - command printf "${COMPLETION_STR}" - fi - - # Source nvm - # shellcheck source=/dev/null - \. "$(nvm_install_dir)/nvm.sh" - - nvm_check_global_modules - - nvm_install_node - - nvm_reset - - echo "=> Close and reopen your terminal to start using nvm or run the following to use it now:" - command printf "${SOURCE_STR}" - if ${BASH_OR_ZSH} ; then - command printf "${COMPLETION_STR}" - fi -} - -# -# Unsets the various functions defined -# during the execution of the install script -# -nvm_reset() { - unset -f nvm_has nvm_install_dir nvm_latest_version nvm_profile_is_bash_or_zsh \ - nvm_source nvm_node_version nvm_download install_nvm_from_git nvm_install_node \ - install_nvm_as_script nvm_try_profile nvm_detect_profile nvm_check_global_modules \ - nvm_do_install nvm_reset nvm_default_install_dir -} - -[ "_$NVM_ENV" = "_testing" ] || nvm_do_install - -} # this ensures the entire script is downloaded # \ No newline at end of file diff --git a/backend/scripts/install-php.sh b/backend/scripts/install-php.sh deleted file mode 100755 index d3d392f4..00000000 --- a/backend/scripts/install-php.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# fail immediately if error -set -e - -# lock global -touch /tmp/install.lock - -# lock -touch /tmp/install-php.lock - -apt-get install -y php - -# unlock global -rm /tmp/install.lock - -# unlock -rm /tmp/install-php.lock diff --git a/backend/scripts/install-ruby.sh b/backend/scripts/install-ruby.sh deleted file mode 100755 index b6bc6fed..00000000 --- a/backend/scripts/install-ruby.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -apt-get update -apt-get install -y curl - -curl -sSL https://get.rvm.io | bash -s stable -source /etc/profile.d/rvm.sh - -echo `rvm list known` -rvm install 2.6.1 - -echo `ruby -v` diff --git a/backend/scripts/install.sh b/backend/scripts/install.sh deleted file mode 100644 index 68c5b3ac..00000000 --- a/backend/scripts/install.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -# fail immediately if error -set -e - -# install node.js -if [ "${CRAWLAB_SERVER_LANG_NODE}" = "Y" ]; -then - echo "installing node.js" - /bin/sh /app/backend/scripts/install-nodejs.sh - echo "installed node.js" -fi - -# install java -if [ "${CRAWLAB_SERVER_LANG_JAVA}" = "Y" ]; -then - echo "installing java" - /bin/sh /app/backend/scripts/install-java.sh - echo "installed java" -fi - -# install dotnet -if [ "${CRAWLAB_SERVER_LANG_DOTNET}" = "Y" ]; -then - echo "installing dotnet" - /bin/sh /app/backend/scripts/install-dotnet.sh - echo "installed dotnet" -fi - -# install php -if [ "${CRAWLAB_SERVER_LANG_PHP}" = "Y" ]; -then - echo "installing php" - /bin/sh /app/backend/scripts/install-php.sh - echo "installed php" -fi - -# install go -if [ "${CRAWLAB_SERVER_LANG_GO}" = "Y" ]; -then - echo "installing go" - /bin/sh /app/backend/scripts/install-go.sh - echo "installed go" -fi diff --git a/backend/services/auth.go b/backend/services/auth.go deleted file mode 100644 index 096d9f14..00000000 --- a/backend/services/auth.go +++ /dev/null @@ -1,20 +0,0 @@ -package services - -import ( - "crawlab/constants" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" -) - -func GetAuthQuery(query bson.M, c *gin.Context) bson.M { - user := GetCurrentUser(c) - if user.Role == constants.RoleAdmin { - // 获得所有数据 - return query - } else { - // 只获取自己的数据 - query["user_id"] = user.Id - return query - } -} - diff --git a/backend/services/challenge/base.go b/backend/services/challenge/base.go deleted file mode 100644 index a7758708..00000000 --- a/backend/services/challenge/base.go +++ /dev/null @@ -1,138 +0,0 @@ -package challenge - -import ( - "crawlab/constants" - "crawlab/model" - "encoding/json" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "io/ioutil" - "path" - "runtime/debug" -) - -type Service interface { - Check() (bool, error) -} - -func GetService(name string, uid bson.ObjectId) Service { - switch name { - case constants.ChallengeLogin7d: - return &Login7dService{UserId: uid} - case constants.ChallengeLogin30d: - return &Login30dService{UserId: uid} - case constants.ChallengeLogin90d: - return &Login90dService{UserId: uid} - case constants.ChallengeLogin180d: - return &Login180dService{UserId: uid} - case constants.ChallengeCreateCustomizedSpider: - return &CreateCustomizedSpiderService{UserId: uid} - case constants.ChallengeCreateConfigurableSpider: - return &CreateConfigurableSpiderService{UserId: uid} - case constants.ChallengeCreateSchedule: - return &CreateScheduleService{UserId: uid} - case constants.ChallengeCreateNodes: - return &CreateNodesService{UserId: uid} - case constants.ChallengeRunRandom: - return &RunRandomService{UserId: uid} - case constants.ChallengeScrape1k: - return &Scrape1kService{UserId: uid} - case constants.ChallengeScrape10k: - return &Scrape10kService{UserId: uid} - case constants.ChallengeScrape100k: - return &Scrape100kService{UserId: uid} - case constants.ChallengeInstallDep: - return &InstallDepService{UserId: uid} - case constants.ChallengeInstallLang: - return &InstallLangService{UserId: uid} - case constants.ChallengeViewDisclaimer: - return &ViewDisclaimerService{UserId: uid} - case constants.ChallengeCreateUser: - return &CreateUserService{UserId: uid} - } - return nil -} - -func AddChallengeAchievement(name string, uid bson.ObjectId) error { - ch, err := model.GetChallengeByName(name) - if err != nil { - return err - } - ca := model.ChallengeAchievement{ - ChallengeId: ch.Id, - UserId: uid, - } - if err := ca.Add(); err != nil { - return err - } - return nil -} - -func CheckChallengeAndUpdate(ch model.Challenge, uid bson.ObjectId) error { - svc := GetService(ch.Name, uid) - achieved, err := svc.Check() - if err != nil { - return err - } - if achieved && !ch.Achieved { - if err := AddChallengeAchievement(ch.Name, uid); err != nil { - return err - } - } - return nil -} - -func CheckChallengeAndUpdateAll(uid bson.ObjectId) error { - challenges, err := model.GetChallengeListWithAchieved(nil, 0, constants.Infinite, "-_id", uid) - if err != nil { - return err - } - for _, ch := range challenges { - if err := CheckChallengeAndUpdate(ch, uid); err != nil { - continue - } - } - return nil -} - -func InitChallengeService() error { - // 读取文件 - contentBytes, err := ioutil.ReadFile(path.Join("data", "challenge_data.json")) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 反序列化 - var challenges []model.Challenge - if err := json.Unmarshal(contentBytes, &challenges); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - for _, ch := range challenges { - chDb, err := model.GetChallengeByName(ch.Name) - if err != nil { - continue - } - if chDb.Name == "" { - if err := ch.Add(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - } else { - ch.Id = chDb.Id - ch.CreateTs = chDb.CreateTs - if err := ch.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - } - } - - return nil -} diff --git a/backend/services/challenge/create_configurable_spider.go b/backend/services/challenge/create_configurable_spider.go deleted file mode 100644 index 45e969f7..00000000 --- a/backend/services/challenge/create_configurable_spider.go +++ /dev/null @@ -1,23 +0,0 @@ -package challenge - -import ( - "crawlab/constants" - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type CreateConfigurableSpiderService struct { - UserId bson.ObjectId -} - -func (s *CreateConfigurableSpiderService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - "type": constants.Configurable, - } - _, count, err := model.GetSpiderList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return count > 0, nil -} diff --git a/backend/services/challenge/create_customized_spider.go b/backend/services/challenge/create_customized_spider.go deleted file mode 100644 index 6c61318f..00000000 --- a/backend/services/challenge/create_customized_spider.go +++ /dev/null @@ -1,23 +0,0 @@ -package challenge - -import ( - "crawlab/constants" - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type CreateCustomizedSpiderService struct { - UserId bson.ObjectId -} - -func (s *CreateCustomizedSpiderService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - "type": constants.Customized, - } - _, count, err := model.GetSpiderList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return count > 0, nil -} diff --git a/backend/services/challenge/create_nodes.go b/backend/services/challenge/create_nodes.go deleted file mode 100644 index 42ec25f7..00000000 --- a/backend/services/challenge/create_nodes.go +++ /dev/null @@ -1,22 +0,0 @@ -package challenge - -import ( - "crawlab/constants" - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type CreateNodesService struct { - UserId bson.ObjectId -} - -func (s *CreateNodesService) Check() (bool, error) { - query := bson.M{ - "status": constants.StatusOnline, - } - list, err := model.GetScheduleList(query) - if err != nil { - return false, err - } - return len(list) >= 3, nil -} diff --git a/backend/services/challenge/create_schedule.go b/backend/services/challenge/create_schedule.go deleted file mode 100644 index 3e0ce0e1..00000000 --- a/backend/services/challenge/create_schedule.go +++ /dev/null @@ -1,21 +0,0 @@ -package challenge - -import ( - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type CreateScheduleService struct { - UserId bson.ObjectId -} - -func (s *CreateScheduleService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - } - list, err := model.GetScheduleList(query) - if err != nil { - return false, err - } - return len(list) > 0, nil -} diff --git a/backend/services/challenge/create_user.go b/backend/services/challenge/create_user.go deleted file mode 100644 index e0272801..00000000 --- a/backend/services/challenge/create_user.go +++ /dev/null @@ -1,21 +0,0 @@ -package challenge - -import ( - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type CreateUserService struct { - UserId bson.ObjectId -} - -func (s *CreateUserService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - } - list, err := model.GetUserList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return len(list) > 0, nil -} diff --git a/backend/services/challenge/install_dep.go b/backend/services/challenge/install_dep.go deleted file mode 100644 index 4730249e..00000000 --- a/backend/services/challenge/install_dep.go +++ /dev/null @@ -1,23 +0,0 @@ -package challenge - -import ( - "crawlab/constants" - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type InstallDepService struct { - UserId bson.ObjectId -} - -func (s *InstallDepService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - "type": constants.ActionTypeInstallDep, - } - list, err := model.GetActionList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return len(list) > 0, nil -} diff --git a/backend/services/challenge/install_lang.go b/backend/services/challenge/install_lang.go deleted file mode 100644 index 15732a2f..00000000 --- a/backend/services/challenge/install_lang.go +++ /dev/null @@ -1,23 +0,0 @@ -package challenge - -import ( - "crawlab/constants" - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type InstallLangService struct { - UserId bson.ObjectId -} - -func (s *InstallLangService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - "type": constants.ActionTypeInstallLang, - } - list, err := model.GetActionList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return len(list) > 0, nil -} diff --git a/backend/services/challenge/login_180d.go b/backend/services/challenge/login_180d.go deleted file mode 100644 index 96cc9e26..00000000 --- a/backend/services/challenge/login_180d.go +++ /dev/null @@ -1,18 +0,0 @@ -package challenge - -import ( - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type Login180dService struct { - UserId bson.ObjectId -} - -func (s *Login180dService) Check() (bool, error) { - days, err := model.GetVisitDays(s.UserId) - if err != nil { - return false, err - } - return days >= 180, nil -} diff --git a/backend/services/challenge/login_30d.go b/backend/services/challenge/login_30d.go deleted file mode 100644 index 5234d5fe..00000000 --- a/backend/services/challenge/login_30d.go +++ /dev/null @@ -1,18 +0,0 @@ -package challenge - -import ( - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type Login30dService struct { - UserId bson.ObjectId -} - -func (s *Login30dService) Check() (bool, error) { - days, err := model.GetVisitDays(s.UserId) - if err != nil { - return false, err - } - return days >= 30, nil -} diff --git a/backend/services/challenge/login_7d.go b/backend/services/challenge/login_7d.go deleted file mode 100644 index 91540423..00000000 --- a/backend/services/challenge/login_7d.go +++ /dev/null @@ -1,18 +0,0 @@ -package challenge - -import ( - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type Login7dService struct { - UserId bson.ObjectId -} - -func (s *Login7dService) Check() (bool, error) { - days, err := model.GetVisitDays(s.UserId) - if err != nil { - return false, err - } - return days >= 7, nil -} diff --git a/backend/services/challenge/login_90d.go b/backend/services/challenge/login_90d.go deleted file mode 100644 index a8526b87..00000000 --- a/backend/services/challenge/login_90d.go +++ /dev/null @@ -1,18 +0,0 @@ -package challenge - -import ( - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type Login90dService struct { - UserId bson.ObjectId -} - -func (s *Login90dService) Check() (bool, error) { - days, err := model.GetVisitDays(s.UserId) - if err != nil { - return false, err - } - return days >= 90, nil -} diff --git a/backend/services/challenge/run_random.go b/backend/services/challenge/run_random.go deleted file mode 100644 index 30c63f0c..00000000 --- a/backend/services/challenge/run_random.go +++ /dev/null @@ -1,25 +0,0 @@ -package challenge - -import ( - "crawlab/constants" - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type RunRandomService struct { - UserId bson.ObjectId -} - -func (s *RunRandomService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - "run_type": constants.RunTypeRandom, - "status": constants.StatusFinished, - "schedule_id": bson.ObjectIdHex(constants.ObjectIdNull), - } - list, err := model.GetTaskList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return len(list) > 0, nil -} diff --git a/backend/services/challenge/scrape_100k.go b/backend/services/challenge/scrape_100k.go deleted file mode 100644 index 68a90eda..00000000 --- a/backend/services/challenge/scrape_100k.go +++ /dev/null @@ -1,24 +0,0 @@ -package challenge - -import ( - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type Scrape100kService struct { - UserId bson.ObjectId -} - -func (s *Scrape100kService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - "result_count": bson.M{ - "$gte": 100000, - }, - } - list, err := model.GetTaskList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return len(list) > 0, nil -} diff --git a/backend/services/challenge/scrape_10k.go b/backend/services/challenge/scrape_10k.go deleted file mode 100644 index ae70b450..00000000 --- a/backend/services/challenge/scrape_10k.go +++ /dev/null @@ -1,24 +0,0 @@ -package challenge - -import ( - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type Scrape10kService struct { - UserId bson.ObjectId -} - -func (s *Scrape10kService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - "result_count": bson.M{ - "$gte": 10000, - }, - } - list, err := model.GetTaskList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return len(list) > 0, nil -} diff --git a/backend/services/challenge/scrape_1k.go b/backend/services/challenge/scrape_1k.go deleted file mode 100644 index cad2469f..00000000 --- a/backend/services/challenge/scrape_1k.go +++ /dev/null @@ -1,24 +0,0 @@ -package challenge - -import ( - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type Scrape1kService struct { - UserId bson.ObjectId -} - -func (s *Scrape1kService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - "result_count": bson.M{ - "$gte": 1000, - }, - } - list, err := model.GetTaskList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return len(list) > 0, nil -} diff --git a/backend/services/challenge/view_disclaimer.go b/backend/services/challenge/view_disclaimer.go deleted file mode 100644 index fc9fe21c..00000000 --- a/backend/services/challenge/view_disclaimer.go +++ /dev/null @@ -1,23 +0,0 @@ -package challenge - -import ( - "crawlab/constants" - "crawlab/model" - "github.com/globalsign/mgo/bson" -) - -type ViewDisclaimerService struct { - UserId bson.ObjectId -} - -func (s *ViewDisclaimerService) Check() (bool, error) { - query := bson.M{ - "user_id": s.UserId, - "type": constants.ActionTypeViewDisclaimer, - } - list, err := model.GetActionList(query, 0, 1, "-_id") - if err != nil { - return false, err - } - return len(list) > 0, nil -} diff --git a/backend/services/clean.go b/backend/services/clean.go deleted file mode 100644 index bbd3571d..00000000 --- a/backend/services/clean.go +++ /dev/null @@ -1,122 +0,0 @@ -package services - -import ( - "crawlab/constants" - "crawlab/model" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "runtime/debug" -) - -func InitTaskCleanUserIds() { - adminUser, err := GetAdminUser() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - tasks, err := model.GetTaskList(nil, 0, constants.Infinite, "+_id") - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - for _, t := range tasks { - if !t.ScheduleId.Valid() { - t.ScheduleId = bson.ObjectIdHex(constants.ObjectIdNull) - if err := t.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - } - - if !t.UserId.Valid() { - t.UserId = adminUser.Id - if err := t.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - } - } -} - -func InitProjectCleanUserIds() { - adminUser, err := GetAdminUser() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - projects, err := model.GetProjectList(nil, "+_id") - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - for _, p := range projects { - if !p.UserId.Valid() { - p.UserId = adminUser.Id - if err := p.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - } - } -} - -func InitSpiderCleanUserIds() { - adminUser, err := GetAdminUser() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - spiders, _ := model.GetSpiderAllList(nil) - for _, s := range spiders { - if !s.UserId.Valid() { - s.UserId = adminUser.Id - if err := s.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - } - } -} - -func InitScheduleCleanUserIds() { - adminUser, err := GetAdminUser() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - schedules, _ := model.GetScheduleList(nil) - for _, s := range schedules { - if !s.UserId.Valid() { - s.UserId = adminUser.Id - if err := s.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - continue - } - } - } -} - -func InitCleanService() error { - if model.IsMaster() { - // 清理任务UserIds - InitTaskCleanUserIds() - // 清理项目UserIds - InitProjectCleanUserIds() - // 清理爬虫UserIds - InitSpiderCleanUserIds() - // 清理定时任务UserIds - InitScheduleCleanUserIds() - } - return nil -} diff --git a/backend/services/config_spider.go b/backend/services/config_spider.go deleted file mode 100644 index c2135bed..00000000 --- a/backend/services/config_spider.go +++ /dev/null @@ -1,278 +0,0 @@ -package services - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/entity" - "crawlab/model" - "crawlab/model/config_spider" - "crawlab/services/spider_handler" - "crawlab/utils" - "errors" - "fmt" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - uuid "github.com/satori/go.uuid" - "github.com/spf13/viper" - "gopkg.in/yaml.v2" - "os" - "path/filepath" - "runtime/debug" - "strings" -) - -func GenerateConfigSpiderFiles(spider model.Spider, configData entity.ConfigSpiderData) error { - // 校验Spiderfile正确性 - if err := ValidateSpiderfile(configData); err != nil { - return err - } - - // 构造代码生成器 - generator := config_spider.ScrapyGenerator{ - Spider: spider, - ConfigData: configData, - } - - // 生成代码 - if err := generator.Generate(); err != nil { - return err - } - - return nil -} - -// 验证Spiderfile -func ValidateSpiderfile(configData entity.ConfigSpiderData) error { - // 获取所有字段 - fields := config_spider.GetAllFields(configData) - - // 校验是否存在 start_url - if configData.StartUrl == "" { - return errors.New("spiderfile invalid: start_url is empty") - } - - // 校验是否存在 start_stage - if configData.StartStage == "" { - return errors.New("spiderfile invalid: start_stage is empty") - } - - // 校验是否存在 stages - if len(configData.Stages) == 0 { - return errors.New("spiderfile invalid: stages is empty") - } - - // 校验stages - dict := map[string]int{} - for _, stage := range configData.Stages { - stageName := stage.Name - - // stage 名称不能为空 - if stageName == "" { - return errors.New("spiderfile invalid: stage name is empty") - } - - // stage 名称不能为保留字符串 - // NOTE: 如果有其他Engine,可以扩展,默认为Scrapy - if configData.Engine == "" || configData.Engine == constants.EngineScrapy { - if strings.Contains(constants.ScrapyProtectedStageNames, stageName) { - return errors.New(fmt.Sprintf("spiderfile invalid: stage name '%s' is protected", stageName)) - } - } else { - return errors.New(fmt.Sprintf("spiderfile invalid: engine '%s' is not implemented", configData.Engine)) - } - - // stage 名称不能重复 - if dict[stageName] == 1 { - return errors.New(fmt.Sprintf("spiderfile invalid: stage name '%s' is duplicated", stageName)) - } - dict[stageName] = 1 - - // stage 字段不能为空 - if len(stage.Fields) == 0 { - return errors.New(fmt.Sprintf("spiderfile invalid: stage '%s' has no fields", stageName)) - } - - // 是否包含 next_stage - hasNextStage := false - - // 遍历字段列表 - for _, field := range stage.Fields { - // stage 的 next stage 只能有一个 - if field.NextStage != "" { - if hasNextStage { - return errors.New(fmt.Sprintf("spiderfile invalid: stage '%s' has more than 1 next_stage", stageName)) - } - hasNextStage = true - } - - // 字段里 css 和 xpath 只能包含一个 - if field.Css != "" && field.Xpath != "" { - return errors.New(fmt.Sprintf("spiderfile invalid: field '%s' in stage '%s' has both css and xpath set which is prohibited", field.Name, stageName)) - } - } - - // stage 里 page_css 和 page_xpath 只能包含一个 - if stage.PageCss != "" && stage.PageXpath != "" { - return errors.New(fmt.Sprintf("spiderfile invalid: stage '%s' has both page_css and page_xpath set which is prohibited", stageName)) - } - - // stage 里 list_css 和 list_xpath 只能包含一个 - if stage.ListCss != "" && stage.ListXpath != "" { - return errors.New(fmt.Sprintf("spiderfile invalid: stage '%s' has both list_css and list_xpath set which is prohibited", stageName)) - } - - // 如果 stage 的 is_list 为 true 但 list_css 为空,报错 - if stage.IsList && (stage.ListCss == "" && stage.ListXpath == "") { - return errors.New("spiderfile invalid: stage with is_list = true should have either list_css or list_xpath being set") - } - } - - // 校验字段唯一性 - if !IsUniqueConfigSpiderFields(fields) { - return errors.New("spiderfile invalid: fields not unique") - } - - // 字段名称不能为保留字符串 - for _, field := range fields { - if strings.Contains(constants.ScrapyProtectedFieldNames, field.Name) { - return errors.New(fmt.Sprintf("spiderfile invalid: field name '%s' is protected", field.Name)) - } - } - - return nil -} - -func IsUniqueConfigSpiderFields(fields []entity.Field) bool { - dict := map[string]int{} - for _, field := range fields { - if dict[field.Name] == 1 { - return false - } - dict[field.Name] = 1 - } - return true -} - -func ProcessSpiderFilesFromConfigData(spider model.Spider, configData entity.ConfigSpiderData) error { - spiderDir := spider.Src - - // 删除已有的爬虫文件 - for _, fInfo := range utils.ListDir(spiderDir) { - // 不删除Spiderfile - if fInfo.Name() == "Spiderfile" { - continue - } - - // 删除其他文件 - if err := os.RemoveAll(filepath.Join(spiderDir, fInfo.Name())); err != nil { - return err - } - } - - // 拷贝爬虫文件 - tplDir := "./template/scrapy" - for _, fInfo := range utils.ListDir(tplDir) { - // 跳过Spiderfile - if fInfo.Name() == "Spiderfile" { - continue - } - - srcPath := filepath.Join(tplDir, fInfo.Name()) - if fInfo.IsDir() { - dirPath := filepath.Join(spiderDir, fInfo.Name()) - if err := utils.CopyDir(srcPath, dirPath); err != nil { - return err - } - } else { - if err := utils.CopyFile(srcPath, filepath.Join(spiderDir, fInfo.Name())); err != nil { - return err - } - } - } - - // 更改爬虫文件 - if err := GenerateConfigSpiderFiles(spider, configData); err != nil { - return err - } - - // 打包为 zip 文件 - files, err := utils.GetFilesFromDir(spiderDir) - if err != nil { - return err - } - randomId := uuid.NewV4() - tmpFilePath := filepath.Join(viper.GetString("other.tmppath"), spider.Name+"."+randomId.String()+".zip") - spiderZipFileName := spider.Name + ".zip" - if err := utils.Compress(files, tmpFilePath); err != nil { - return err - } - - // 获取 GridFS 实例 - s, gf := database.GetGridFs("files") - defer s.Close() - - // 判断文件是否已经存在 - var gfFile model.GridFs - if err := gf.Find(bson.M{"filename": spiderZipFileName}).One(&gfFile); err == nil { - // 已经存在文件,则删除 - if err := gf.RemoveId(gfFile.Id); err != nil { - log.Errorf("remove grid fs error: %s", err.Error()) - debug.PrintStack() - return err - } - } - - // 上传到GridFs - fid, err := RetryUploadToGridFs(spiderZipFileName, tmpFilePath) - if err != nil { - log.Errorf("upload to grid fs error: %s", err.Error()) - return err - } - - // 保存爬虫 FileId - spider.FileId = fid - _ = spider.Save() - - // 获取爬虫同步实例 - spiderSync := spider_handler.SpiderSync{ - Spider: spider, - } - - // 获取gfFile - gfFile2 := model.GetGridFs(spider.FileId) - - // 生成MD5 - spiderSync.CreateMd5File(gfFile2.Md5) - - return nil -} - -func GenerateSpiderfileFromConfigData(spider model.Spider, configData entity.ConfigSpiderData) error { - // Spiderfile 路径 - sfPath := filepath.Join(spider.Src, "Spiderfile") - - // 生成Yaml内容 - sfContentByte, err := yaml.Marshal(configData) - if err != nil { - return err - } - - // 打开文件 - var f *os.File - if utils.Exists(sfPath) { - f, err = os.OpenFile(sfPath, os.O_WRONLY|os.O_TRUNC, 0777) - } else { - f, err = os.OpenFile(sfPath, os.O_CREATE, 0777) - } - if err != nil { - return err - } - defer f.Close() - - // 写入内容 - if _, err := f.Write(sfContentByte); err != nil { - return err - } - - return nil -} diff --git a/backend/services/context/context.go b/backend/services/context/context.go deleted file mode 100644 index 760be3d7..00000000 --- a/backend/services/context/context.go +++ /dev/null @@ -1,99 +0,0 @@ -package context - -import ( - "crawlab/constants" - "crawlab/errors" - "crawlab/model" - "fmt" - "github.com/apex/log" - "github.com/gin-gonic/gin" - "github.com/go-playground/validator/v10" - errors2 "github.com/pkg/errors" - "net/http" - "runtime/debug" -) - -type Context struct { - *gin.Context -} - -func (c *Context) User() *model.User { - userIfe, exists := c.Get(constants.ContextUser) - if !exists { - return nil - } - user, ok := userIfe.(*model.User) - if !ok { - return nil - } - return user -} -func (c *Context) Success(data interface{}, metas ...interface{}) { - var meta interface{} - if len(metas) == 0 { - meta = gin.H{} - } else { - meta = metas[0] - } - if data == nil { - data = gin.H{} - } - c.JSON(http.StatusOK, gin.H{ - "status": "ok", - "message": "success", - "data": data, - "meta": meta, - "error": "", - }) -} -func (c *Context) Failed(err error, variables ...interface{}) { - c.failed(err, http.StatusOK, variables...) -} -func (c *Context) failed(err error, httpCode int, variables ...interface{}) { - errStr := err.Error() - if len(variables) > 0 { - errStr = fmt.Sprintf(errStr, variables...) - } - log.Errorf("handle error:" + errStr) - debug.PrintStack() - causeError := errors2.Cause(err) - switch causeError.(type) { - case errors.OPError: - opError := causeError.(errors.OPError) - - c.AbortWithStatusJSON(opError.HttpCode, gin.H{ - "status": "ok", - "message": "error", - "error": errStr, - }) - - case validator.ValidationErrors: - validatorErrors := causeError.(validator.ValidationErrors) - //firstError := validatorErrors[0].(validator.FieldError) - c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{ - "status": "ok", - "message": "error", - "error": validatorErrors.Error(), - }) - default: - fmt.Println("deprecated....") - c.AbortWithStatusJSON(httpCode, gin.H{ - "status": "ok", - "message": "error", - "error": errStr, - }) - } -} -func (c *Context) FailedWithError(err error, httpCode ...int) { - - var code = 200 - if len(httpCode) > 0 { - code = httpCode[0] - } - c.failed(err, code) - -} - -func WithGinContext(context *gin.Context) *Context { - return &Context{Context: context} -} diff --git a/backend/services/doc.go b/backend/services/doc.go deleted file mode 100644 index 572e5cb4..00000000 --- a/backend/services/doc.go +++ /dev/null @@ -1,27 +0,0 @@ -package services - -import ( - "github.com/apex/log" - "github.com/imroc/req" - "runtime/debug" -) - -func GetDocs() (data string, err error) { - // 获取远端数据 - res, err := req.Get("https://docs.crawlab.cn/search_plus_index.json") - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return data, err - } - - // 反序列化 - data, err = res.ToString() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return data, err - } - - return data, nil -} diff --git a/backend/services/file.go b/backend/services/file.go deleted file mode 100644 index d126fcab..00000000 --- a/backend/services/file.go +++ /dev/null @@ -1,65 +0,0 @@ -package services - -import ( - "crawlab/model" - "github.com/apex/log" - "os" - "path" - "runtime/debug" - "strings" -) - -func GetFileNodeTree(dstPath string, level int) (f model.File, err error) { - return getFileNodeTree(dstPath, level, dstPath) -} - -func getFileNodeTree(dstPath string, level int, rootPath string) (f model.File, err error) { - dstF, err := os.Open(dstPath) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return f, err - } - defer dstF.Close() - fileInfo, err := dstF.Stat() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return f, nil - } - if !fileInfo.IsDir() { //如果dstF是文件 - return model.File{ - Label: fileInfo.Name(), - Name: fileInfo.Name(), - Path: strings.Replace(dstPath, rootPath, "", -1), - IsDir: false, - Size: fileInfo.Size(), - Children: nil, - }, nil - } else { //如果dstF是文件夹 - dir, err := dstF.Readdir(0) //获取文件夹下各个文件或文件夹的fileInfo - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return f, nil - } - f = model.File{ - Label: path.Base(dstPath), - Name: path.Base(dstPath), - Path: strings.Replace(dstPath, rootPath, "", -1), - IsDir: true, - Size: 0, - Children: nil, - } - for _, subFileInfo := range dir { - subFileNode, err := getFileNodeTree(path.Join(dstPath, subFileInfo.Name()), level+1, rootPath) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return f, err - } - f.Children = append(f.Children, subFileNode) - } - return f, nil - } -} diff --git a/backend/services/git.go b/backend/services/git.go deleted file mode 100644 index 97d4ba52..00000000 --- a/backend/services/git.go +++ /dev/null @@ -1,603 +0,0 @@ -package services - -import ( - "crawlab/lib/cron" - "crawlab/model" - "crawlab/services/spider_handler" - "crawlab/utils" - "fmt" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "gopkg.in/src-d/go-git.v4" - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh" - "gopkg.in/src-d/go-git.v4/storage/memory" - "io/ioutil" - "net/url" - "os" - "path" - "regexp" - "runtime/debug" - "strings" - "time" -) - -var GitCron *GitCronScheduler - -type GitCronScheduler struct { - cron *cron.Cron -} - -type GitBranch struct { - Hash string `json:"hash"` - Name string `json:"name"` - Label string `json:"label"` -} - -type GitTag struct { - Hash string `json:"hash"` - Name string `json:"name"` - Label string `json:"label"` -} - -type GitCommit struct { - Hash string `json:"hash"` - TreeHash string `json:"tree_hash"` - Author string `json:"author"` - Email string `json:"email"` - Message string `json:"message"` - IsHead bool `json:"is_head"` - Ts time.Time `json:"ts"` - Branches []GitBranch `json:"branches"` - RemoteBranches []GitBranch `json:"remote_branches"` - Tags []GitTag `json:"tags"` -} - -func (g *GitCronScheduler) Start() error { - c := cron.New(cron.WithSeconds()) - - // 启动cron服务 - g.cron.Start() - - // 更新任务列表 - if err := g.Update(); err != nil { - log.Errorf("update scheduler error: %s", err.Error()) - debug.PrintStack() - return err - } - - // 每30秒更新一次任务列表 - spec := "*/30 * * * * *" - if _, err := c.AddFunc(spec, UpdateGitCron); err != nil { - log.Errorf("add func update schedulers error: %s", err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func (g *GitCronScheduler) RemoveAll() { - entries := g.cron.Entries() - for i := 0; i < len(entries); i++ { - g.cron.Remove(entries[i].ID) - } -} - -func (g *GitCronScheduler) Update() error { - // 删除所有定时任务 - g.RemoveAll() - - // 获取开启 Git 自动同步的爬虫 - spiders, err := model.GetSpiderAllList(bson.M{"git_auto_sync": true}) - if err != nil { - log.Errorf("get spider list error: %s", err.Error()) - debug.PrintStack() - return err - } - - // 遍历任务列表 - for _, s := range spiders { - // 添加到定时任务 - if err := g.AddJob(s); err != nil { - log.Errorf("add job error: %s, job: %s, cron: %s", err.Error(), s.Name, s.GitSyncFrequency) - debug.PrintStack() - return err - } - } - - return nil -} - -func (g *GitCronScheduler) AddJob(s model.Spider) error { - spec := s.GitSyncFrequency - - // 添加定时任务 - _, err := g.cron.AddFunc(spec, AddGitCronJob(s)) - if err != nil { - log.Errorf("add func task error: %s", err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -// 保存爬虫Git同步错误 -func SaveSpiderGitSyncError(s model.Spider, errMsg string) { - s, _ = model.GetSpider(s.Id) - s.GitSyncError = errMsg - if err := s.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } -} - -// 获得Git分支 -func GetGitRemoteBranchesPlain(gitUrl string, username string, password string) (branches []string, err error) { - storage := memory.NewStorage() - u, _ := url.Parse(gitUrl) - var listOptions git.ListOptions - if strings.HasPrefix(gitUrl, "http") { - gitUrl = fmt.Sprintf( - "%s://%s:%s@%s%s", - u.Scheme, - username, - password, - u.Hostname(), - u.Path, - ) - } else { - auth, err := ssh.NewPublicKeysFromFile(username, path.Join(os.Getenv("HOME"), ".ssh", "id_rsa"), "") - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return branches, err - } - listOptions = git.ListOptions{ - Auth: auth, - } - } - remote := git.NewRemote(storage, &config.RemoteConfig{ - URLs: []string{ - gitUrl, - }}) - rfs, err := remote.List(&listOptions) - if err != nil { - return - } - for _, rf := range rfs { - if rf.Type() == plumbing.SymbolicReference { - continue - } - regex := regexp.MustCompile("refs/heads/(.*)$") - res := regex.FindStringSubmatch(rf.String()) - if len(res) > 1 { - branches = append(branches, res[1]) - } - } - - return branches, nil -} - -// 重置爬虫Git -func ResetSpiderGit(s model.Spider) (err error) { - // 删除文件夹 - if err := os.RemoveAll(s.Src); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 创建空文件夹 - if err := os.MkdirAll(s.Src, os.ModePerm); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 同步到GridFS - if err := UploadSpiderToGridFsFromMaster(s); err != nil { - return err - } - - return nil -} - -// 同步爬虫Git -func SyncSpiderGit(s model.Spider) (err error) { - // 如果 .git 不存在,初始化一个仓库 - if !utils.Exists(path.Join(s.Src, ".git")) { - _, err := git.PlainInit(s.Src, false) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return err - } - } - - // 打开 repo - repo, err := git.PlainOpen(s.Src) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - SaveSpiderGitSyncError(s, err.Error()) - return err - } - - // 生成 URL - gitUrl := s.GitUrl - if s.GitUsername != "" && s.GitPassword != "" { - u, err := url.Parse(s.GitUrl) - if err != nil { - SaveSpiderGitSyncError(s, err.Error()) - return err - } - gitUrl = fmt.Sprintf( - "%s://%s:%s@%s%s", - u.Scheme, - s.GitUsername, - s.GitPassword, - u.Hostname(), - u.Path, - ) - } - - // 创建 remote - _ = repo.DeleteRemote("origin") - _, err = repo.CreateRemote(&config.RemoteConfig{ - Name: "origin", - URLs: []string{gitUrl}, - }) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - SaveSpiderGitSyncError(s, err.Error()) - return err - } - - // 生成验证信息 - var auth ssh.AuthMethod - if !strings.HasPrefix(s.GitUrl, "http") { - // 为 SSH - regex := regexp.MustCompile("^(?:ssh://?)?([0-9a-zA-Z_]+)@") - res := regex.FindStringSubmatch(s.GitUrl) - username := s.GitUsername - if username == "" { - if len(res) > 1 { - username = res[1] - } else { - username = "git" - } - } - auth, err = ssh.NewPublicKeysFromFile(username, path.Join(os.Getenv("HOME"), ".ssh", "id_rsa"), "") - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - SaveSpiderGitSyncError(s, err.Error()) - return err - } - } - - // 获取 repo - _ = repo.Fetch(&git.FetchOptions{ - RemoteName: "origin", - Force: true, - Auth: auth, - Tags: git.AllTags, - }) - - // 获得 WorkTree - wt, err := repo.Worktree() - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - SaveSpiderGitSyncError(s, err.Error()) - return err - } - - // 拉取 repo - if err := wt.Pull(&git.PullOptions{ - RemoteName: "origin", - Auth: auth, - ReferenceName: plumbing.HEAD, - SingleBranch: false, - }); err != nil { - if err.Error() == "already up-to-date" { - // 检查是否为 Scrapy - sync := spider_handler.SpiderSync{Spider: s} - sync.CheckIsScrapy() - - // 同步到GridFS - if err := UploadSpiderToGridFsFromMaster(s); err != nil { - SaveSpiderGitSyncError(s, err.Error()) - return err - } - - // 如果没有错误,则保存空字符串 - SaveSpiderGitSyncError(s, "") - - return nil - } - log.Error(err.Error()) - debug.PrintStack() - SaveSpiderGitSyncError(s, err.Error()) - return err - } - - // 切换分支 - if err := wt.Checkout(&git.CheckoutOptions{ - Branch: plumbing.NewBranchReferenceName(s.GitBranch), - }); err != nil { - log.Error(err.Error()) - debug.PrintStack() - SaveSpiderGitSyncError(s, err.Error()) - return err - } - - // 同步到GridFS - if err := UploadSpiderToGridFsFromMaster(s); err != nil { - SaveSpiderGitSyncError(s, err.Error()) - return err - } - - // 获取更新后的爬虫 - s, err = model.GetSpider(s.Id) - if err != nil { - SaveSpiderGitSyncError(s, err.Error()) - return err - } - - // 检查是否为 Scrapy - sync := spider_handler.SpiderSync{Spider: s} - sync.CheckIsScrapy() - - // 如果没有错误,则保存空字符串 - SaveSpiderGitSyncError(s, "") - - return nil -} - -// 添加Git定时任务 -func AddGitCronJob(s model.Spider) func() { - return func() { - if err := SyncSpiderGit(s); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - } -} - -// 更新Git定时任务 -func UpdateGitCron() { - if err := GitCron.Update(); err != nil { - log.Errorf(err.Error()) - return - } -} - -// 获取SSH公钥 -func GetGitSshPublicKey() string { - if !utils.Exists(path.Join(os.Getenv("HOME"), ".ssh")) || - !utils.Exists(path.Join(os.Getenv("HOME"), ".ssh", "id_rsa")) || - !utils.Exists(path.Join(os.Getenv("HOME"), ".ssh", "id_rsa.pub")) { - log.Errorf("no ssh public key") - debug.PrintStack() - return "" - } - content, err := ioutil.ReadFile(path.Join(os.Getenv("HOME"), ".ssh", "id_rsa.pub")) - if err != nil { - return "" - } - return string(content) -} - -// 获取Git分支 -func GetGitBranches(s model.Spider) (branches []GitBranch, err error) { - // 打开 repo - repo, err := git.PlainOpen(s.Src) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return branches, err - } - - iter, err := repo.Branches() - if iter == nil { - return branches, nil - } - if err := iter.ForEach(func(reference *plumbing.Reference) error { - branches = append(branches, GitBranch{ - Hash: reference.Hash().String(), - Name: reference.Name().String(), - Label: reference.Name().Short(), - }) - return nil - }); err != nil { - return branches, err - } - - return branches, nil -} - -// 获取Git Tags -func GetGitTags(s model.Spider) (tags []GitTag, err error) { - // 打开 repo - repo, err := git.PlainOpen(s.Src) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return tags, err - } - - iter, err := repo.Tags() - if iter == nil { - return tags, nil - } - if err := iter.ForEach(func(reference *plumbing.Reference) error { - tags = append(tags, GitTag{ - Hash: reference.Hash().String(), - Name: reference.Name().String(), - Label: reference.Name().Short(), - }) - return nil - }); err != nil { - return tags, err - } - - return tags, nil -} - -// 获取Git Head Hash -func GetGitHeadHash(repo *git.Repository) string { - head, _ := repo.Head() - return head.Hash().String() -} - -// 获取Git远端分支 -func GetGitRemoteBranches(s model.Spider) (branches []GitBranch, err error) { - // 打开 repo - repo, err := git.PlainOpen(s.Src) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return branches, err - } - - iter, err := repo.References() - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return branches, err - } - if err := iter.ForEach(func(reference *plumbing.Reference) error { - if reference.Name().IsRemote() { - log.Infof(reference.Hash().String()) - log.Infof(reference.Name().String()) - branches = append(branches, GitBranch{ - Hash: reference.Hash().String(), - Name: reference.Name().String(), - Label: reference.Name().Short(), - }) - } - return nil - }); err != nil { - log.Error(err.Error()) - debug.PrintStack() - return branches, err - } - return branches, err -} - -// 获取Git Commits -func GetGitCommits(s model.Spider) (commits []GitCommit, err error) { - // 打开 repo - repo, err := git.PlainOpen(s.Src) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return commits, err - } - - // 获取分支列表 - branches, err := GetGitBranches(s) - branchesDict := map[string][]GitBranch{} - for _, b := range branches { - branchesDict[b.Hash] = append(branchesDict[b.Hash], b) - } - - // 获取分支列表 - remoteBranches, err := GetGitRemoteBranches(s) - remoteBranchesDict := map[string][]GitBranch{} - for _, b := range remoteBranches { - remoteBranchesDict[b.Hash] = append(remoteBranchesDict[b.Hash], b) - } - - // 获取标签列表 - tags, err := GetGitTags(s) - tagsDict := map[string][]GitTag{} - for _, t := range tags { - tagsDict[t.Hash] = append(tagsDict[t.Hash], t) - } - - // 获取日志遍历器 - iter, err := repo.Log(&git.LogOptions{ - All: true, - }) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return commits, err - } - - // 遍历日志 - if err := iter.ForEach(func(commit *object.Commit) error { - gc := GitCommit{ - Hash: commit.Hash.String(), - TreeHash: commit.TreeHash.String(), - Message: commit.Message, - Author: commit.Author.Name, - Email: commit.Author.Email, - Ts: commit.Author.When, - IsHead: commit.Hash.String() == GetGitHeadHash(repo), - Branches: branchesDict[commit.Hash.String()], - RemoteBranches: remoteBranchesDict[commit.Hash.String()], - Tags: tagsDict[commit.Hash.String()], - } - commits = append(commits, gc) - return nil - }); err != nil { - log.Error(err.Error()) - debug.PrintStack() - return commits, err - } - - return commits, nil -} - -func GitCheckout(s model.Spider, hash string) (err error) { - // 打开 repo - repo, err := git.PlainOpen(s.Src) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return err - } - - // 获取worktree - wt, err := repo.Worktree() - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return err - } - //判断远程origin路径是否和当前的GitUrl是同一个,如果不是删掉原来的路径,重新拉取远程代码 - remote, err := repo.Remote("origin") - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return err - } - if remote.String() != s.GitUrl { - utils.RemoveFiles(s.Src) - return SyncSpiderGit(s) - } - - // Checkout - if err := wt.Checkout(&git.CheckoutOptions{ - Hash: plumbing.NewHash(hash), - Create: false, - Force: true, - Keep: false, - }); err != nil { - log.Error(err.Error()) - debug.PrintStack() - return err - } - - return nil -} diff --git a/backend/services/local_node/local_node.go b/backend/services/local_node/local_node.go deleted file mode 100644 index ad1321ca..00000000 --- a/backend/services/local_node/local_node.go +++ /dev/null @@ -1,25 +0,0 @@ -package local_node - -import ( - "crawlab/model" - "github.com/spf13/viper" -) - -func GetLocalNode() *LocalNode { - return localNode -} -func CurrentNode() *model.Node { - return GetLocalNode().Current() -} - -func InitLocalNode() (node *LocalNode, err error) { - registerType := viper.GetString("server.register.type") - ip := viper.GetString("server.register.ip") - customNodeName := viper.GetString("server.register.customNodeName") - - localNode, err = NewLocalNode(ip, customNodeName, registerType) - if err != nil { - return nil, err - } - return localNode, err -} diff --git a/backend/services/local_node/mongo_info.go b/backend/services/local_node/mongo_info.go deleted file mode 100644 index d8d4df06..00000000 --- a/backend/services/local_node/mongo_info.go +++ /dev/null @@ -1,62 +0,0 @@ -package local_node - -import ( - "crawlab/model" - "github.com/apex/log" - "github.com/cenkalti/backoff/v4" - "go.uber.org/atomic" - "sync" - "time" -) - -var locker atomic.Int32 - -type mongo struct { - node *model.Node - sync.RWMutex -} - -func (n *mongo) load(retry bool) (err error) { - n.Lock() - defer n.Unlock() - var node model.Node - if retry { - b := backoff.NewConstantBackOff(1 * time.Second) - err = backoff.Retry(func() error { - node, err = model.GetNodeByKey(GetLocalNode().Identify) - if err != nil { - log.WithError(err).Warnf("Get current node info from database failed. Will after %f seconds, try again.", b.NextBackOff().Seconds()) - } - return err - }, b) - } else { - node, err = model.GetNodeByKey(localNode.Identify) - } - - if err != nil { - return - } - n.node = &node - return nil -} -func (n *mongo) watch() { - timer := time.NewTicker(time.Second * 5) - for range timer.C { - if locker.CAS(0, 1) { - - err := n.load(false) - - if err != nil { - log.WithError(err).Errorf("load current node from database failed") - } - locker.Store(0) - } - continue - } -} - -func (n *mongo) Current() *model.Node { - n.RLock() - defer n.RUnlock() - return n.node -} diff --git a/backend/services/local_node/node_info.go b/backend/services/local_node/node_info.go deleted file mode 100644 index d037da6d..00000000 --- a/backend/services/local_node/node_info.go +++ /dev/null @@ -1,74 +0,0 @@ -package local_node - -import ( - "errors" - "github.com/hashicorp/go-sockaddr" - "os" -) - -var localNode *LocalNode - -type IdentifyType string - -const ( - Ip = IdentifyType("ip") - Mac = IdentifyType("mac") - Hostname = IdentifyType("hostname") -) - -type local struct { - Ip string - Mac string - Hostname string - Identify string - IdentifyType IdentifyType -} -type LocalNode struct { - local - mongo -} - -func (l *LocalNode) Ready() error { - err := localNode.load(true) - if err != nil { - return err - } - go localNode.watch() - return nil -} - -func NewLocalNode(ip string, identify string, identifyTypeString string) (node *LocalNode, err error) { - addrs, err := sockaddr.GetPrivateInterfaces() - if ip == "" { - if err != nil { - return node, err - } - if len(addrs) == 0 { - return node, errors.New("address not found") - } - ipaddr := *sockaddr.ToIPAddr(addrs[0].SockAddr) - ip = ipaddr.NetIP().String() - } - - mac := addrs[0].HardwareAddr.String() - hostname, err := os.Hostname() - if err != nil { - return node, err - } - local := local{Ip: ip, Mac: mac, Hostname: hostname} - switch IdentifyType(identifyTypeString) { - case Ip: - local.Identify = local.Ip - local.IdentifyType = Ip - case Mac: - local.Identify = local.Mac - local.IdentifyType = Mac - case Hostname: - local.Identify = local.Hostname - local.IdentifyType = Hostname - default: - local.Identify = identify - local.IdentifyType = IdentifyType(identifyTypeString) - } - return &LocalNode{local: local, mongo: mongo{}}, nil -} diff --git a/backend/services/log.go b/backend/services/log.go deleted file mode 100644 index 3e95a3d8..00000000 --- a/backend/services/log.go +++ /dev/null @@ -1,188 +0,0 @@ -package services - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/entity" - "crawlab/lib/cron" - "crawlab/model" - "crawlab/utils" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "github.com/spf13/viper" - "io/ioutil" - "os" - "path/filepath" - "runtime/debug" - "time" -) - -// 任务日志频道映射 -var TaskLogChanMap = utils.NewChanMap() - -// 定时删除日志 -func DeleteLogPeriodically() { - logDir := viper.GetString("log.path") - if !utils.Exists(logDir) { - log.Error("Can Not Set Delete Logs Periodically,No Log Dir") - return - } - rd, err := ioutil.ReadDir(logDir) - if err != nil { - log.Error("Read Log Dir Failed") - return - } - - for _, fi := range rd { - if fi.IsDir() { - log.Info(filepath.Join(logDir, fi.Name())) - _ = os.RemoveAll(filepath.Join(logDir, fi.Name())) - log.Info("Delete Log File Success") - } - } - -} - -// 删除本地日志 -func RemoveLocalLog(path string) error { - if err := model.RemoveFile(path); err != nil { - log.Error("remove local file error: " + err.Error()) - return err - } - return nil -} - -// 删除远程日志 -func RemoveRemoteLog(task model.Task) error { - msg := entity.NodeMessage{ - Type: constants.MsgTypeRemoveLog, - LogPath: task.LogPath, - TaskId: task.Id, - } - // 发布获取日志消息 - channel := "nodes:" + task.NodeId.Hex() - if _, err := database.RedisClient.Publish(channel, utils.GetJson(msg)); err != nil { - log.Errorf("publish redis error: %s", err.Error()) - debug.PrintStack() - return err - } - return nil -} - -// 删除日志文件 -func RemoveLogByTaskId(id string) error { - t, err := model.GetTask(id) - if err != nil { - log.Error("get task error:" + err.Error()) - return err - } - removeLog(t) - - return nil -} - -func RemoveLogByTaskStatus(status string) error { - tasks, err := model.GetTaskList(bson.M{"status": status}, 0, constants.Infinite, "-create_ts") - if err != nil { - log.Error("get tasks error:" + err.Error()) - return err - } - for _, task := range tasks { - RemoveLogByTaskId(task.Id) - } - return nil -} - -func removeLog(t model.Task) { - if err := RemoveLocalLog(t.LogPath); err != nil { - log.Errorf("remove local log error: %s", err.Error()) - debug.PrintStack() - } - if err := RemoveRemoteLog(t); err != nil { - log.Errorf("remove remote log error: %s", err.Error()) - debug.PrintStack() - } -} - -// 删除日志文件 -func RemoveLogBySpiderId(id bson.ObjectId) error { - tasks, err := model.GetTaskList(bson.M{"spider_id": id}, 0, constants.Infinite, "-create_ts") - if err != nil { - log.Errorf("get tasks error: %s", err.Error()) - debug.PrintStack() - } - for _, task := range tasks { - removeLog(task) - } - return nil -} - -// 初始化定时删除日志 -func InitDeleteLogPeriodically() error { - c := cron.New(cron.WithSeconds()) - if _, err := c.AddFunc(viper.GetString("log.deleteFrequency"), DeleteLogPeriodically); err != nil { - return err - } - - c.Start() - return nil -} - -func InitLogIndexes() error { - s, c := database.GetCol("logs") - defer s.Close() - se, ce := database.GetCol("error_logs") - defer se.Close() - - _ = c.EnsureIndex(mgo.Index{ - Key: []string{"task_id", "seq"}, - }) - _ = c.EnsureIndex(mgo.Index{ - Key: []string{"task_id", "msg"}, - }) - _ = c.EnsureIndex(mgo.Index{ - Key: []string{"expire_ts"}, - Sparse: true, - ExpireAfter: 1 * time.Second, - }) - _ = ce.EnsureIndex(mgo.Index{ - Key: []string{"task_id"}, - }) - _ = ce.EnsureIndex(mgo.Index{ - Key: []string{"log_id"}, - }) - _ = ce.EnsureIndex(mgo.Index{ - Key: []string{"expire_ts"}, - Sparse: true, - ExpireAfter: 1 * time.Second, - }) - - return nil -} - -func InitLogService() error { - logLevel := viper.GetString("log.level") - if logLevel != "" { - log.SetLevelFromString(logLevel) - } - log.Info("initialized log config successfully") - if viper.GetString("log.isDeletePeriodically") == "Y" { - if err := InitDeleteLogPeriodically(); err != nil { - log.Error("init DeletePeriodically failed") - return err - } - log.Info("initialized periodically cleaning log successfully") - } else { - log.Info("periodically cleaning log is switched off") - } - - if model.IsMaster() { - if err := InitLogIndexes(); err != nil { - log.Errorf(err.Error()) - return err - } - } - - return nil -} diff --git a/backend/services/log_test.go b/backend/services/log_test.go deleted file mode 100644 index 1e3f76d4..00000000 --- a/backend/services/log_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package services - -import ( - "crawlab/config" - "crawlab/utils" - "fmt" - "github.com/apex/log" - . "github.com/smartystreets/goconvey/convey" - "github.com/spf13/viper" - "os" - "testing" -) - -func TestDeleteLogPeriodically(t *testing.T) { - Convey("Test DeleteLogPeriodically", t, func() { - err := config.InitConfig("../conf/config.yml") - So(err, ShouldBeNil) - log.Info("初始化配置成功") - logDir := viper.GetString("log.path") - log.Info(logDir) - DeleteLogPeriodically() - }) -} - -func TestGetLocalLog(t *testing.T) { - //create a log file for test - logPath := "../logs/crawlab/test.log" - f, err := os.Create(logPath) - defer utils.Close(f) - if err != nil { - fmt.Println(err) - - } else { - _, err = f.WriteString("This is for test") - fmt.Println(err) - } - - //delete the test log file - _ = os.Remove(logPath) - -} diff --git a/backend/services/msg_handler/handler.go b/backend/services/msg_handler/handler.go deleted file mode 100644 index bee4113c..00000000 --- a/backend/services/msg_handler/handler.go +++ /dev/null @@ -1,37 +0,0 @@ -package msg_handler - -import ( - "crawlab/constants" - "crawlab/entity" - "github.com/apex/log" -) - -type Handler interface { - Handle() error -} - -func GetMsgHandler(msg entity.NodeMessage) Handler { - log.Debugf("received msg , type is : %s", msg.Type) - //if msg.Type == constants.MsgTypeGetLog || msg.Type == constants.MsgTypeRemoveLog { - // // 日志相关 - // return &Log{ - // msg: msg, - // } - //} else if msg.Type == constants.MsgTypeCancelTask { - // // 任务相关 - // return &Task{ - // msg: msg, - // } - if msg.Type == constants.MsgTypeGetSystemInfo { - // 系统信息相关 - return &SystemInfo{ - msg: msg, - } - } else if msg.Type == constants.MsgTypeRemoveSpider { - // 爬虫相关 - return &Spider{ - SpiderId: msg.SpiderId, - } - } - return nil -} diff --git a/backend/services/msg_handler/msg_log.go b/backend/services/msg_handler/msg_log.go deleted file mode 100644 index 2a17ed99..00000000 --- a/backend/services/msg_handler/msg_log.go +++ /dev/null @@ -1,54 +0,0 @@ -package msg_handler - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/entity" - "crawlab/model" - "crawlab/utils" - "github.com/apex/log" - "runtime/debug" -) - -type Log struct { - msg entity.NodeMessage -} - -func (g *Log) Handle() error { - if g.msg.Type == constants.MsgTypeGetLog { - return g.get() - } else if g.msg.Type == constants.MsgTypeRemoveLog { - return g.remove() - } - return nil -} - -func (g *Log) get() error { - // 发出的消息 - msgSd := entity.NodeMessage{ - Type: constants.MsgTypeGetLog, - TaskId: g.msg.TaskId, - } - // 获取本地日志 - logStr, err := model.GetLocalLog(g.msg.LogPath) - if err != nil { - log.Errorf("get node local log error: %s", err.Error()) - debug.PrintStack() - msgSd.Error = err.Error() - msgSd.Log = err.Error() - } else { - msgSd.Log = utils.BytesToString(logStr) - } - // 发布消息给主节点 - if err := database.Pub(constants.ChannelMasterNode, msgSd); err != nil { - log.Errorf("pub log to master node error: %s", err.Error()) - debug.PrintStack() - return err - } - log.Infof(msgSd.Log) - return nil -} - -func (g *Log) remove() error { - return model.RemoveFile(g.msg.LogPath) -} diff --git a/backend/services/msg_handler/msg_spider.go b/backend/services/msg_handler/msg_spider.go deleted file mode 100644 index dcd6ce06..00000000 --- a/backend/services/msg_handler/msg_spider.go +++ /dev/null @@ -1,24 +0,0 @@ -package msg_handler - -import ( - "crawlab/model" - "crawlab/utils" - "github.com/globalsign/mgo/bson" - "github.com/spf13/viper" - "path/filepath" -) - -type Spider struct { - SpiderId string -} - -func (s *Spider) Handle() error { - // 移除本地的爬虫目录 - spider, err := model.GetSpider(bson.ObjectIdHex(s.SpiderId)) - if err != nil { - return err - } - path := filepath.Join(viper.GetString("spider.path"), spider.Name) - utils.RemoveFiles(path) - return nil -} diff --git a/backend/services/msg_handler/msg_system_info.go b/backend/services/msg_handler/msg_system_info.go deleted file mode 100644 index 9de5c74a..00000000 --- a/backend/services/msg_handler/msg_system_info.go +++ /dev/null @@ -1,29 +0,0 @@ -package msg_handler - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/entity" - "crawlab/model" -) - -type SystemInfo struct { - msg entity.NodeMessage -} - -func (s *SystemInfo) Handle() error { - // 获取环境信息 - sysInfo, err := model.GetLocalSystemInfo() - if err != nil { - return err - } - msgSd := entity.NodeMessage{ - Type: constants.MsgTypeGetSystemInfo, - NodeId: s.msg.NodeId, - SysInfo: sysInfo, - } - if err := database.Pub(constants.ChannelMasterNode, msgSd); err != nil { - return err - } - return nil -} diff --git a/backend/services/msg_handler/msg_task.go b/backend/services/msg_handler/msg_task.go deleted file mode 100644 index 21b95430..00000000 --- a/backend/services/msg_handler/msg_task.go +++ /dev/null @@ -1,40 +0,0 @@ -package msg_handler - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/model" - "crawlab/utils" - "github.com/apex/log" - "runtime/debug" - "time" -) - -type Task struct { - msg entity.NodeMessage -} - -func (t *Task) Handle() error { - log.Infof("received cancel task msg, task_id: %s", t.msg.TaskId) - // 取消任务 - ch := utils.TaskExecChanMap.ChanBlocked(t.msg.TaskId) - if ch != nil { - ch <- constants.TaskCancel - } else { - log.Infof("chan is empty, update status to abnormal") - // 节点可能被重启,找不到chan - task, err := model.GetTask(t.msg.TaskId) - if err != nil { - log.Errorf("task not found, task_id: %s", t.msg.TaskId) - debug.PrintStack() - return err - } - task.Status = constants.StatusAbnormal - task.FinishTs = time.Now() - if err := task.Save(); err != nil { - debug.PrintStack() - log.Infof("cancel task error: %s", err.Error()) - } - } - return nil -} diff --git a/backend/services/node.go b/backend/services/node.go deleted file mode 100644 index e3ef237a..00000000 --- a/backend/services/node.go +++ /dev/null @@ -1,255 +0,0 @@ -package services - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/model" - "crawlab/services/local_node" - "crawlab/utils" - "encoding/json" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "runtime/debug" - "time" -) - -type Data struct { - Key string `json:"key"` - Mac string `json:"mac"` - Ip string `json:"ip"` - Hostname string `json:"hostname"` - Name string `json:"name"` - NameType string `json:"name_type"` - - Master bool `json:"master"` - UpdateTs time.Time `json:"update_ts"` - UpdateTsUnix int64 `json:"update_ts_unix"` -} - -// 所有调用IsMasterNode的方法,都永远会在master节点执行,所以GetCurrentNode方法返回永远是master节点 -// 该ID的节点是否为主节点 -func IsMasterNode(id string) bool { - curNode := local_node.CurrentNode() - //curNode, _ := model.GetCurrentNode() - node, _ := model.GetNode(bson.ObjectIdHex(id)) - return curNode.Id == node.Id -} - -// 获取节点数据 -func GetNodeData() (Data, error) { - localNode := local_node.GetLocalNode() - key := localNode.Identify - if key == "" { - return Data{}, nil - } - - value, err := database.RedisClient.HGet("nodes", key) - data := Data{} - if err := json.Unmarshal([]byte(value), &data); err != nil { - return data, err - } - return data, err -} -func GetRedisNode(key string) (*Data, error) { - // 获取节点数据 - value, err := database.RedisClient.HGet("nodes", key) - if err != nil { - log.Errorf(err.Error()) - return nil, err - } - - // 解析节点列表数据 - var data Data - if err := json.Unmarshal([]byte(value), &data); err != nil { - log.Errorf(err.Error()) - return nil, err - } - return &data, nil -} - -// 更新所有节点状态 -func UpdateNodeStatus() { - // 从Redis获取节点keys - list, err := database.RedisClient.HScan("nodes") - if err != nil { - log.Errorf("get redis node keys error: %s", err.Error()) - return - } - var offlineKeys []string - // 遍历节点keys - for _, dataStr := range list { - var data Data - if err := json.Unmarshal([]byte(dataStr), &data); err != nil { - log.Errorf(err.Error()) - continue - } - // 如果记录的更新时间超过60秒,该节点被认为离线 - if time.Now().Unix()-data.UpdateTsUnix > 60 { - offlineKeys = append(offlineKeys, data.Key) - // 在Redis中删除该节点 - if err := database.RedisClient.HDel("nodes", data.Key); err != nil { - log.Errorf("delete redis node key error:%s, key:%s", err.Error(), data.Key) - } - continue - } - - // 处理node信息 - if err = UpdateNodeInfo(&data); err != nil { - log.Errorf(err.Error()) - continue - } - } - if len(offlineKeys) > 0 { - s, c := database.GetCol("nodes") - defer s.Close() - _, err = c.UpdateAll(bson.M{ - "key": bson.M{ - "$in": offlineKeys, - }, - }, bson.M{ - "$set": bson.M{ - "status": constants.StatusOffline, - "update_ts": time.Now(), - "update_ts_unix": time.Now().Unix(), - }, - }) - if err != nil { - log.Errorf(err.Error()) - } - } -} - -// 处理节点信息 -func UpdateNodeInfo(data *Data) (err error) { - // 更新节点信息到数据库 - s, c := database.GetCol("nodes") - defer s.Close() - - _, err = c.Upsert(bson.M{"key": data.Key}, bson.M{ - "$set": bson.M{ - "status": constants.StatusOnline, - "key": data.Key, - "name_type": data.NameType, - "ip": data.Ip, - "port": "8000", - "mac": data.Mac, - "is_master": data.Master, - "update_ts": time.Now(), - "update_ts_unix": time.Now().Unix(), - }, - "$setOnInsert": bson.M{ - "name": data.Name, - "_id": bson.NewObjectId(), - }, - }) - return err -} - -// 更新节点数据 -func UpdateNodeData() { - localNode := local_node.GetLocalNode() - key := localNode.Identify - // 构造节点数据 - data := Data{ - Key: key, - Mac: localNode.Mac, - Ip: localNode.Ip, - Hostname: localNode.Hostname, - Name: localNode.Identify, - NameType: string(localNode.IdentifyType), - Master: model.IsMaster(), - UpdateTs: time.Now(), - UpdateTsUnix: time.Now().Unix(), - } - - // 注册节点到Redis - dataBytes, err := json.Marshal(&data) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - - if err := database.RedisClient.HSet("nodes", key, utils.BytesToString(dataBytes)); err != nil { - log.Errorf(err.Error()) - return - } -} - -// 发送心跳信息到Redis,每5秒发送一次 -func SendHeartBeat() { - for { - UpdateNodeData() - time.Sleep(5 * time.Second) - } -} - -// 每10秒刷新一次节点信息 -func UpdateNodeStatusPeriodically() { - for { - UpdateNodeStatus() - time.Sleep(10 * time.Second) - } -} - -// 每60秒更新异常节点信息 -func UpdateOfflineNodeTaskToAbnormalPeriodically() { - for { - nodes, err := model.GetNodeList(bson.M{"status": constants.StatusOffline}) - if err != nil { - log.Errorf("get nodes error: " + err.Error()) - debug.PrintStack() - continue - } - for _, n := range nodes { - if err := model.UpdateTaskToAbnormal(n.Id); err != nil { - log.Errorf("update task to abnormal error: " + err.Error()) - debug.PrintStack() - continue - } - } - time.Sleep(60 * time.Second) - } -} - -// 初始化节点服务 -func InitNodeService() error { - node, err := local_node.InitLocalNode() - if err != nil { - return err - } - - // 每5秒更新一次本节点信息 - go SendHeartBeat() - - // 首次更新节点数据(注册到Redis) - UpdateNodeData() - if model.IsMaster() { - err = model.UpdateMasterNodeInfo(node.Identify, node.Ip, node.Mac, node.Hostname) - if err != nil { - return err - } - } - - // 节点准备完毕 - if err = node.Ready(); err != nil { - return err - } - - // 如果为主节点 - if model.IsMaster() { - // 每10秒刷新所有节点信息 - go UpdateNodeStatusPeriodically() - - // 每60秒更新离线节点任务为异常 - go UpdateOfflineNodeTaskToAbnormalPeriodically() - } - - // 更新在当前节点执行中的任务状态为:abnormal - if err := model.UpdateTaskToAbnormal(node.Current().Id); err != nil { - debug.PrintStack() - return err - } - - return nil -} diff --git a/backend/services/notification/mail.go b/backend/services/notification/mail.go deleted file mode 100644 index 2231151b..00000000 --- a/backend/services/notification/mail.go +++ /dev/null @@ -1,138 +0,0 @@ -package notification - -import ( - "errors" - "github.com/apex/log" - "github.com/matcornic/hermes" - "gopkg.in/gomail.v2" - "net/mail" - "os" - "runtime/debug" - "strconv" -) - -func SendMail(toEmail string, toName string, subject string, content string) error { - // hermes instance - h := hermes.Hermes{ - Theme: new(hermes.Default), - Product: hermes.Product{ - Name: "Crawlab Team", - Copyright: "© 2019 Crawlab, Made by Crawlab-Team", - }, - } - - // config - port, _ := strconv.Atoi(os.Getenv("CRAWLAB_NOTIFICATION_MAIL_PORT")) - password := os.Getenv("CRAWLAB_NOTIFICATION_MAIL_SMTP_PASSWORD") - SMTPUser := os.Getenv("CRAWLAB_NOTIFICATION_MAIL_SMTP_USER") - smtpConfig := smtpAuthentication{ - Server: os.Getenv("CRAWLAB_NOTIFICATION_MAIL_SERVER"), - Port: port, - SenderEmail: os.Getenv("CRAWLAB_NOTIFICATION_MAIL_SENDEREMAIL"), - SenderIdentity: os.Getenv("CRAWLAB_NOTIFICATION_MAIL_SENDERIDENTITY"), - SMTPPassword: password, - SMTPUser: SMTPUser, - } - options := sendOptions{ - To: toEmail, - Subject: subject, - } - - // email instance - email := hermes.Email{ - Body: hermes.Body{ - Name: toName, - FreeMarkdown: hermes.Markdown(content + GetFooter()), - }, - } - - // generate html - html, err := h.GenerateHTML(email) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // generate text - text, err := h.GeneratePlainText(email) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // send the email - if err := send(smtpConfig, options, html, text); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -type smtpAuthentication struct { - Server string - Port int - SenderEmail string - SenderIdentity string - SMTPUser string - SMTPPassword string -} - -// sendOptions are options for sending an email -type sendOptions struct { - To string - Subject string -} - -// send sends the email -func send(smtpConfig smtpAuthentication, options sendOptions, htmlBody string, txtBody string) error { - - if smtpConfig.Server == "" { - return errors.New("SMTP server config is empty") - } - if smtpConfig.Port == 0 { - return errors.New("SMTP port config is empty") - } - - if smtpConfig.SMTPUser == "" { - return errors.New("SMTP user is empty") - } - - if smtpConfig.SenderIdentity == "" { - return errors.New("SMTP sender identity is empty") - } - - if smtpConfig.SenderEmail == "" { - return errors.New("SMTP sender email is empty") - } - - if options.To == "" { - return errors.New("no receiver emails configured") - } - - from := mail.Address{ - Name: smtpConfig.SenderIdentity, - Address: smtpConfig.SenderEmail, - } - - m := gomail.NewMessage() - m.SetHeader("From", from.String()) - m.SetHeader("To", options.To) - m.SetHeader("Subject", options.Subject) - - m.SetBody("text/plain", txtBody) - m.AddAlternative("text/html", htmlBody) - - d := gomail.NewPlainDialer(smtpConfig.Server, smtpConfig.Port, smtpConfig.SMTPUser, smtpConfig.SMTPPassword) - - return d.DialAndSend(m) -} - -func GetFooter() string { - return ` -[Github](https://github.com/crawlab-team/crawlab) | [Documentation](http://docs.crawlab.cn) | [Docker](https://hub.docker.com/r/tikazyq/crawlab) -` -} diff --git a/backend/services/notification/mobile.go b/backend/services/notification/mobile.go deleted file mode 100644 index e140ecc5..00000000 --- a/backend/services/notification/mobile.go +++ /dev/null @@ -1,59 +0,0 @@ -package notification - -import ( - "errors" - "github.com/apex/log" - "github.com/imroc/req" - "runtime/debug" -) - -func SendMobileNotification(webhook string, title string, content string) error { - type ResBody struct { - ErrCode int `json:"errcode"` - ErrMsg string `json:"errmsg"` - } - - // 请求头 - header := req.Header{ - "Content-Type": "application/json; charset=utf-8", - } - - // 请求数据 - data := req.Param{ - "msgtype": "markdown", - "markdown": req.Param{ - "title": title, - "text": content, - "content": content, - }, - "at": req.Param{ - "atMobiles": []string{}, - "isAtAll": false, - }, - } - - // 发起请求 - res, err := req.Post(webhook, header, req.BodyJSON(&data)) - if err != nil { - log.Errorf("dingtalk notification error: " + err.Error()) - debug.PrintStack() - return err - } - - // 解析响应 - var resBody ResBody - if err := res.ToJSON(&resBody); err != nil { - log.Errorf("dingtalk notification error: " + err.Error()) - debug.PrintStack() - return err - } - - // 判断响应是否报错 - if resBody.ErrCode != 0 { - log.Errorf("dingtalk notification error: " + resBody.ErrMsg) - debug.PrintStack() - return errors.New(resBody.ErrMsg) - } - - return nil -} diff --git a/backend/services/repo.go b/backend/services/repo.go deleted file mode 100644 index a2afb8cd..00000000 --- a/backend/services/repo.go +++ /dev/null @@ -1,93 +0,0 @@ -package services - -import ( - "crawlab/constants" - "crawlab/model" - "crawlab/utils" - "fmt" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "github.com/imroc/req" - uuid "github.com/satori/go.uuid" - "github.com/spf13/viper" - "path" - "path/filepath" - "runtime/debug" - "strings" -) - -func DownloadRepo(fullName string, userId bson.ObjectId) (err error) { - // 下载 zip 文件 - url := fmt.Sprintf("%s/%s.zip", viper.GetString("repo.ossUrl"), fullName) - progress := func(current, total int64) { - fmt.Println(float32(current)/float32(total)*100, "%") - } - res, err := req.Get(url, req.DownloadProgress(progress)) - if err != nil { - log.Errorf("download repo error: " + err.Error()) - debug.PrintStack() - return err - } - spiderName := strings.Replace(fullName, "/", "_", -1) - randomId := uuid.NewV4() - tmpFilePath := filepath.Join(viper.GetString("other.tmppath"), spiderName+"."+randomId.String()+".zip") - if err := res.ToFile(tmpFilePath); err != nil { - log.Errorf("to file error: " + err.Error()) - debug.PrintStack() - return err - } - - // 解压 zip 文件 - tmpFile := utils.OpenFile(tmpFilePath) - if err := utils.DeCompress(tmpFile, viper.GetString("other.tmppath")); err != nil { - log.Errorf("de-compress error: " + err.Error()) - debug.PrintStack() - return err - } - - // 拷贝文件 - spiderPath := path.Join(viper.GetString("spider.path"), spiderName) - srcDirPath := fmt.Sprintf("%s/data/github.com/%s", viper.GetString("other.tmppath"), fullName) - if err := utils.CopyDir(srcDirPath, spiderPath); err != nil { - log.Errorf("copy error: " + err.Error()) - debug.PrintStack() - return err - } - - // 创建爬虫 - spider := model.GetSpiderByName(spiderName) - if spider.Name == "" { - // 新增 - spider = model.Spider{ - Id: bson.NewObjectId(), - Name: spiderName, - DisplayName: spiderName, - Type: constants.Customized, - Src: spiderPath, - ProjectId: bson.ObjectIdHex(constants.ObjectIdNull), - FileId: bson.ObjectIdHex(constants.ObjectIdNull), - UserId: userId, - } - if err := spider.Add(); err != nil { - log.Error("add spider error: " + err.Error()) - debug.PrintStack() - return err - } - } else { - // 更新 - if err := spider.Save(); err != nil { - log.Error("save spider error: " + err.Error()) - debug.PrintStack() - return err - } - } - - // 上传爬虫 - if err := UploadSpiderToGridFsFromMaster(spider); err != nil { - log.Error("upload spider error: " + err.Error()) - debug.PrintStack() - return err - } - - return nil -} diff --git a/backend/services/rpc/base.go b/backend/services/rpc/base.go deleted file mode 100644 index 866fe48b..00000000 --- a/backend/services/rpc/base.go +++ /dev/null @@ -1,146 +0,0 @@ -package rpc - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/entity" - "crawlab/model" - "crawlab/services/local_node" - "crawlab/utils" - "encoding/json" - "errors" - "fmt" - "github.com/apex/log" - "github.com/cenkalti/backoff/v4" - "github.com/gomodule/redigo/redis" - uuid "github.com/satori/go.uuid" - "runtime/debug" -) - -// RPC服务基础类 -type Service interface { - ServerHandle() (entity.RpcMessage, error) - ClientHandle() (interface{}, error) -} - -// 客户端处理消息函数 -func ClientFunc(msg entity.RpcMessage) func() (entity.RpcMessage, error) { - return func() (replyMsg entity.RpcMessage, err error) { - // 请求ID - msg.Id = uuid.NewV4().String() - - // 发送RPC消息 - msgStr := utils.ObjectToString(msg) - if err := database.RedisClient.LPush(fmt.Sprintf("rpc:%s", msg.NodeId), msgStr); err != nil { - log.Errorf("RpcClientFunc error: " + err.Error()) - debug.PrintStack() - return replyMsg, err - } - - // 获取RPC回复消息 - dataStr, err := database.RedisClient.BRPop(fmt.Sprintf("rpc:%s:%s", msg.NodeId, msg.Id), msg.Timeout) - if err != nil { - log.Errorf("RpcClientFunc error: " + err.Error()) - debug.PrintStack() - return replyMsg, err - } - - // 反序列化消息 - if err := json.Unmarshal([]byte(dataStr), &replyMsg); err != nil { - log.Errorf("RpcClientFunc error: " + err.Error()) - debug.PrintStack() - return replyMsg, err - } - - // 如果返回消息有错误,返回错误 - if replyMsg.Error != "" { - return replyMsg, errors.New(replyMsg.Error) - } - - return - } -} - -// 获取RPC服务 -func GetService(msg entity.RpcMessage) Service { - switch msg.Method { - case constants.RpcInstallLang: - return &InstallLangService{msg: msg} - case constants.RpcInstallDep: - return &InstallDepService{msg: msg} - case constants.RpcUninstallDep: - return &UninstallDepService{msg: msg} - case constants.RpcGetLang: - return &GetLangService{msg: msg} - case constants.RpcGetInstalledDepList: - return &GetInstalledDepsService{msg: msg} - case constants.RpcCancelTask: - return &CancelTaskService{msg: msg} - case constants.RpcGetSystemInfoService: - return &GetSystemInfoService{msg: msg} - } - return nil -} - -// 处理RPC消息 -func handleMsg(msgStr string, node *model.Node) { - // 反序列化消息 - var msg entity.RpcMessage - if err := json.Unmarshal([]byte(msgStr), &msg); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - - // 获取service - service := GetService(msg) - - // 根据Method调用本地方法 - replyMsg, err := service.ServerHandle() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - - // 发送返回消息 - if err := database.RedisClient.LPush(fmt.Sprintf("rpc:%s:%s", node.Id.Hex(), replyMsg.Id), utils.ObjectToString(replyMsg)); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - } -} - -// 初始化服务端RPC服务 -func InitRpcService() error { - go func() { - node := local_node.CurrentNode() - for { - // 获取当前节点 - //node, err := model.GetCurrentNode() - //if err != nil { - // log.Errorf(err.Error()) - // debug.PrintStack() - // continue - //} - b := backoff.NewExponentialBackOff() - bp := backoff.WithMaxRetries(b, 10) - var msgStr string - var err error - err = backoff.Retry(func() error { - msgStr, err = database.RedisClient.BRPop(fmt.Sprintf("rpc:%s", node.Id.Hex()), 0) - - if err != nil && err != redis.ErrNil { - log.WithError(err).Warnf("waiting for redis pool active connection. will after %f seconds try again.", b.NextBackOff().Seconds()) - return err - } - return err - }, bp) - if err != nil { - continue - } - // 处理消息 - go handleMsg(msgStr, node) - } - }() - return nil -} diff --git a/backend/services/rpc/cancel_task.go b/backend/services/rpc/cancel_task.go deleted file mode 100644 index 0e1d4617..00000000 --- a/backend/services/rpc/cancel_task.go +++ /dev/null @@ -1,63 +0,0 @@ -package rpc - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/model" - "crawlab/utils" - "errors" - "fmt" - "github.com/globalsign/mgo/bson" -) - -type CancelTaskService struct { - msg entity.RpcMessage -} - -func (s *CancelTaskService) ServerHandle() (entity.RpcMessage, error) { - taskId := utils.GetRpcParam("task_id", s.msg.Params) - nodeId := utils.GetRpcParam("node_id", s.msg.Params) - if err := CancelTaskLocal(taskId, nodeId); err != nil { - s.msg.Error = err.Error() - return s.msg, err - } - s.msg.Result = "success" - return s.msg, nil -} - -func (s *CancelTaskService) ClientHandle() (o interface{}, err error) { - // 发起 RPC 请求,获取服务端数据 - _, err = ClientFunc(s.msg)() - if err != nil { - return - } - - return -} - -func CancelTaskLocal(taskId string, nodeId string) error { - if !utils.TaskExecChanMap.HasChanKey(taskId) { - _ = model.UpdateTaskToAbnormal(bson.ObjectIdHex(nodeId)) - return errors.New(fmt.Sprintf("task id (%s) does not exist", taskId)) - } - ch := utils.TaskExecChanMap.ChanBlocked(taskId) - ch <- constants.TaskCancel - return nil -} - -func CancelTaskRemote(taskId string, nodeId string) (err error) { - params := make(map[string]string) - params["task_id"] = taskId - params["node_id"] = nodeId - s := GetService(entity.RpcMessage{ - NodeId: nodeId, - Method: constants.RpcCancelTask, - Params: params, - Timeout: 60, - }) - _, err = s.ClientHandle() - if err != nil { - return - } - return -} diff --git a/backend/services/rpc/get_installed_deps.go b/backend/services/rpc/get_installed_deps.go deleted file mode 100644 index 9017fa64..00000000 --- a/backend/services/rpc/get_installed_deps.go +++ /dev/null @@ -1,123 +0,0 @@ -package rpc - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/utils" - "encoding/json" - "os/exec" - "regexp" - "runtime/debug" - "strings" -) - -type GetInstalledDepsService struct { - msg entity.RpcMessage -} - -func (s *GetInstalledDepsService) ServerHandle() (entity.RpcMessage, error) { - lang := utils.GetRpcParam("lang", s.msg.Params) - deps, err := GetInstalledDepsLocal(lang) - if err != nil { - s.msg.Error = err.Error() - return s.msg, err - } - resultStr, _ := json.Marshal(deps) - s.msg.Result = string(resultStr) - return s.msg, nil -} - -func (s *GetInstalledDepsService) ClientHandle() (o interface{}, err error) { - // 发起 RPC 请求,获取服务端数据 - s.msg, err = ClientFunc(s.msg)() - if err != nil { - return o, err - } - - // 反序列化 - var output []entity.Dependency - if err := json.Unmarshal([]byte(s.msg.Result), &output); err != nil { - return o, err - } - o = output - - return -} - -// 获取本地已安装依赖列表 -func GetInstalledDepsLocal(lang string) (deps []entity.Dependency, err error) { - if lang == constants.Python { - deps, err = GetPythonInstalledDepListLocal() - } else if lang == constants.Nodejs { - deps, err = GetNodejsInstalledDepListLocal() - } - return deps, err -} - -// 获取Python本地已安装依赖列表 -func GetPythonInstalledDepListLocal() ([]entity.Dependency, error) { - var list []entity.Dependency - - cmd := exec.Command("pip", "freeze") - outputBytes, err := cmd.Output() - if err != nil { - debug.PrintStack() - return list, err - } - - for _, line := range strings.Split(string(outputBytes), "\n") { - arr := strings.Split(line, "==") - if len(arr) < 2 { - continue - } - dep := entity.Dependency{ - Name: strings.ToLower(arr[0]), - Version: arr[1], - Installed: true, - } - list = append(list, dep) - } - - return list, nil -} - -// 获取Node.js本地已安装依赖列表 -func GetNodejsInstalledDepListLocal() ([]entity.Dependency, error) { - var list []entity.Dependency - - cmd := exec.Command("npm", "ls", "-g", "--depth", "0") - outputBytes, _ := cmd.Output() - - regex := regexp.MustCompile("\\s(.*)@(.*)") - for _, line := range strings.Split(string(outputBytes), "\n") { - arr := regex.FindStringSubmatch(line) - if len(arr) < 3 { - continue - } - dep := entity.Dependency{ - Name: strings.ToLower(arr[1]), - Version: arr[2], - Installed: true, - } - list = append(list, dep) - } - - return list, nil -} - -func GetInstalledDepsRemote(nodeId string, lang string) (deps []entity.Dependency, err error) { - params := make(map[string]string) - params["lang"] = lang - s := GetService(entity.RpcMessage{ - NodeId: nodeId, - Method: constants.RpcGetInstalledDepList, - Params: params, - Timeout: 60, - }) - o, err := s.ClientHandle() - if err != nil { - return - } - deps = o.([]entity.Dependency) - return -} diff --git a/backend/services/rpc/get_lang.go b/backend/services/rpc/get_lang.go deleted file mode 100644 index 93d8baf1..00000000 --- a/backend/services/rpc/get_lang.go +++ /dev/null @@ -1,82 +0,0 @@ -package rpc - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/utils" - "encoding/json" -) - -type GetLangService struct { - msg entity.RpcMessage -} - -func (s *GetLangService) ServerHandle() (entity.RpcMessage, error) { - langName := utils.GetRpcParam("lang", s.msg.Params) - lang := utils.GetLangFromLangNamePlain(langName) - l := GetLangLocal(lang) - lang.InstallStatus = l.InstallStatus - - // 序列化 - resultStr, _ := json.Marshal(lang) - s.msg.Result = string(resultStr) - return s.msg, nil -} - -func (s *GetLangService) ClientHandle() (o interface{}, err error) { - // 发起 RPC 请求,获取服务端数据 - s.msg, err = ClientFunc(s.msg)() - if err != nil { - return o, err - } - - var output entity.Lang - if err := json.Unmarshal([]byte(s.msg.Result), &output); err != nil { - return o, err - } - o = output - - return -} - -func GetLangLocal(lang entity.Lang) entity.Lang { - // 检查是否存在执行路径 - for _, p := range lang.ExecutablePaths { - if utils.Exists(p) { - lang.InstallStatus = constants.InstallStatusInstalled - return lang - } - } - - //// 检查是否正在安装 - //if utils.Exists(lang.LockPath) { - // lang.InstallStatus = constants.InstallStatusInstalling - // return lang - //} - // - //// 检查其他语言是否在安装 - //if utils.Exists("/tmp/install.lock") { - // lang.InstallStatus = constants.InstallStatusInstallingOther - // return lang - //} - - lang.InstallStatus = constants.InstallStatusNotInstalled - return lang -} - -func GetLangRemote(nodeId string, lang entity.Lang) (l entity.Lang, err error) { - params := make(map[string]string) - params["lang"] = lang.ExecutableName - s := GetService(entity.RpcMessage{ - NodeId: nodeId, - Method: constants.RpcGetLang, - Params: params, - Timeout: 60, - }) - o, err := s.ClientHandle() - if err != nil { - return - } - l = o.(entity.Lang) - return -} diff --git a/backend/services/rpc/get_system_info.go b/backend/services/rpc/get_system_info.go deleted file mode 100644 index 7e290656..00000000 --- a/backend/services/rpc/get_system_info.go +++ /dev/null @@ -1,67 +0,0 @@ -package rpc - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/model" - "encoding/json" -) - -type GetSystemInfoService struct { - msg entity.RpcMessage -} - -func (s *GetSystemInfoService) ServerHandle() (entity.RpcMessage, error) { - sysInfo, err := GetSystemInfoServiceLocal() - if err != nil { - s.msg.Error = err.Error() - return s.msg, err - } - - // 序列化 - resultStr, _ := json.Marshal(sysInfo) - s.msg.Result = string(resultStr) - return s.msg, nil -} - -func (s *GetSystemInfoService) ClientHandle() (o interface{}, err error) { - // 发起 RPC 请求,获取服务端数据 - s.msg, err = ClientFunc(s.msg)() - if err != nil { - return o, err - } - - var output entity.SystemInfo - if err := json.Unmarshal([]byte(s.msg.Result), &output); err != nil { - return o, err - } - o = output - - return -} - -func GetSystemInfoServiceLocal() (sysInfo entity.SystemInfo, err error) { - // 获取环境信息 - sysInfo, err = model.GetLocalSystemInfo() - if err != nil { - return sysInfo, err - } - return sysInfo, nil -} - -func GetSystemInfoServiceRemote(nodeId string) (sysInfo entity.SystemInfo, err error) { - params := make(map[string]string) - params["node_id"] = nodeId - s := GetService(entity.RpcMessage{ - NodeId: nodeId, - Method: constants.RpcGetSystemInfoService, - Params: params, - Timeout: 60, - }) - o, err := s.ClientHandle() - if err != nil { - return - } - sysInfo = o.(entity.SystemInfo) - return -} diff --git a/backend/services/rpc/install_dep.go b/backend/services/rpc/install_dep.go deleted file mode 100644 index e615688a..00000000 --- a/backend/services/rpc/install_dep.go +++ /dev/null @@ -1,100 +0,0 @@ -package rpc - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/utils" - "errors" - "fmt" - "github.com/apex/log" - "os/exec" - "runtime/debug" -) - -type InstallDepService struct { - msg entity.RpcMessage -} - -func (s *InstallDepService) ServerHandle() (entity.RpcMessage, error) { - lang := utils.GetRpcParam("lang", s.msg.Params) - depName := utils.GetRpcParam("dep_name", s.msg.Params) - if err := InstallDepLocal(lang, depName); err != nil { - s.msg.Error = err.Error() - return s.msg, err - } - s.msg.Result = "success" - return s.msg, nil -} - -func (s *InstallDepService) ClientHandle() (o interface{}, err error) { - // 发起 RPC 请求,获取服务端数据 - _, err = ClientFunc(s.msg)() - if err != nil { - return - } - - return -} - -func InstallDepLocal(lang string, depName string) error { - if lang == constants.Python { - _, err := InstallPythonDepLocal(depName) - if err != nil { - return err - } - } else if lang == constants.Nodejs { - _, err := InstallNodejsDepLocal(depName) - if err != nil { - return err - } - } else { - return errors.New(fmt.Sprintf("%s is not implemented", lang)) - } - return nil -} - -// 安装Python本地依赖 -func InstallPythonDepLocal(depName string) (string, error) { - // 依赖镜像URL - url := "https://pypi.tuna.tsinghua.edu.cn/simple" - - cmd := exec.Command("pip", "install", depName, "-i", url) - outputBytes, err := cmd.Output() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return fmt.Sprintf("error: %s", err.Error()), err - } - return string(outputBytes), nil -} - -func InstallNodejsDepLocal(depName string) (string, error) { - // 依赖镜像URL - url := "https://registry.npm.taobao.org" - - cmd := exec.Command("npm", "install", depName, "-g", "--registry", url) - outputBytes, err := cmd.Output() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return fmt.Sprintf("error: %s", err.Error()), err - } - return string(outputBytes), nil -} - -func InstallDepRemote(nodeId string, lang string, depName string) (err error) { - params := make(map[string]string) - params["lang"] = lang - params["dep_name"] = depName - s := GetService(entity.RpcMessage{ - NodeId: nodeId, - Method: constants.RpcInstallDep, - Params: params, - Timeout: 300, - }) - _, err = s.ClientHandle() - if err != nil { - return - } - return -} diff --git a/backend/services/rpc/install_lang.go b/backend/services/rpc/install_lang.go deleted file mode 100644 index 39f5a6d8..00000000 --- a/backend/services/rpc/install_lang.go +++ /dev/null @@ -1,73 +0,0 @@ -package rpc - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/utils" - "errors" - "fmt" - "github.com/apex/log" - "os/exec" - "path" - "runtime/debug" -) - -type InstallLangService struct { - msg entity.RpcMessage -} - -func (s *InstallLangService) ServerHandle() (entity.RpcMessage, error) { - lang := utils.GetRpcParam("lang", s.msg.Params) - output, err := InstallLangLocal(lang) - s.msg.Result = output - if err != nil { - s.msg.Error = err.Error() - return s.msg, err - } - return s.msg, nil -} - -func (s *InstallLangService) ClientHandle() (o interface{}, err error) { - // 发起 RPC 请求,获取服务端数据 - go func() { - _, err := ClientFunc(s.msg)() - if err != nil { - return - } - }() - - return -} - -// 本地安装语言 -func InstallLangLocal(lang string) (o string, err error) { - l := utils.GetLangFromLangNamePlain(lang) - if l.Name == "" || l.InstallScript == "" { - return "", errors.New(fmt.Sprintf("%s is not implemented", lang)) - } - cmd := exec.Command("/bin/sh", path.Join("scripts", l.InstallScript)) - output, err := cmd.Output() - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return string(output), err - } - return -} - -// 远端安装语言 -func InstallLangRemote(nodeId string, lang string) (o string, err error) { - params := make(map[string]string) - params["lang"] = lang - s := GetService(entity.RpcMessage{ - NodeId: nodeId, - Method: constants.RpcInstallLang, - Params: params, - Timeout: 60, - }) - _, err = s.ClientHandle() - if err != nil { - return - } - return -} diff --git a/backend/services/rpc/remove_spider.go b/backend/services/rpc/remove_spider.go deleted file mode 100644 index 1d8ff90c..00000000 --- a/backend/services/rpc/remove_spider.go +++ /dev/null @@ -1,62 +0,0 @@ -package rpc - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/model" - "crawlab/utils" - "github.com/globalsign/mgo/bson" - "github.com/spf13/viper" - "path/filepath" -) - -type RemoveSpiderService struct { - msg entity.RpcMessage -} - -func (s *RemoveSpiderService) ServerHandle() (entity.RpcMessage, error) { - spiderId := utils.GetRpcParam("spider_id", s.msg.Params) - if err := RemoveSpiderServiceLocal(spiderId); err != nil { - s.msg.Error = err.Error() - return s.msg, err - } - s.msg.Result = "success" - return s.msg, nil -} - -func (s *RemoveSpiderService) ClientHandle() (o interface{}, err error) { - // 发起 RPC 请求,获取服务端数据 - _, err = ClientFunc(s.msg)() - if err != nil { - return - } - - return -} - -func RemoveSpiderServiceLocal(spiderId string) error { - // 移除本地的爬虫目录 - spider, err := model.GetSpider(bson.ObjectIdHex(spiderId)) - if err != nil { - return err - } - path := filepath.Join(viper.GetString("spider.path"), spider.Name) - utils.RemoveFiles(path) - return nil -} - -func RemoveSpiderServiceRemote(spiderId string, nodeId string) (err error) { - params := make(map[string]string) - params["spider_id"] = spiderId - s := GetService(entity.RpcMessage{ - NodeId: nodeId, - Method: constants.RpcRemoveSpider, - Params: params, - Timeout: 60, - }) - _, err = s.ClientHandle() - if err != nil { - return - } - return -} diff --git a/backend/services/rpc/uninstall_dep.go b/backend/services/rpc/uninstall_dep.go deleted file mode 100644 index 1b8b8ecb..00000000 --- a/backend/services/rpc/uninstall_dep.go +++ /dev/null @@ -1,96 +0,0 @@ -package rpc - -import ( - "crawlab/constants" - "crawlab/entity" - "crawlab/utils" - "errors" - "fmt" - "github.com/apex/log" - "os/exec" - "runtime/debug" -) - -type UninstallDepService struct { - msg entity.RpcMessage -} - -func (s *UninstallDepService) ServerHandle() (entity.RpcMessage, error) { - lang := utils.GetRpcParam("lang", s.msg.Params) - depName := utils.GetRpcParam("dep_name", s.msg.Params) - if err := UninstallDepLocal(lang, depName); err != nil { - s.msg.Error = err.Error() - return s.msg, err - } - s.msg.Result = "success" - return s.msg, nil -} - -func (s *UninstallDepService) ClientHandle() (o interface{}, err error) { - // 发起 RPC 请求,获取服务端数据 - _, err = ClientFunc(s.msg)() - if err != nil { - return - } - - return -} - -func UninstallDepLocal(lang string, depName string) error { - if lang == constants.Python { - output, err := UninstallPythonDepLocal(depName) - if err != nil { - log.Debugf(output) - return err - } - } else if lang == constants.Nodejs { - output, err := UninstallNodejsDepLocal(depName) - if err != nil { - log.Debugf(output) - return err - } - } else { - return errors.New(fmt.Sprintf("%s is not implemented", lang)) - } - return nil -} - -func UninstallPythonDepLocal(depName string) (string, error) { - cmd := exec.Command("pip", "uninstall", "-y", depName) - outputBytes, err := cmd.Output() - if err != nil { - log.Errorf(string(outputBytes)) - log.Errorf(err.Error()) - debug.PrintStack() - return fmt.Sprintf("error: %s", err.Error()), err - } - return string(outputBytes), nil -} - -func UninstallNodejsDepLocal(depName string) (string, error) { - cmd := exec.Command("npm", "uninstall", depName, "-g") - outputBytes, err := cmd.Output() - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return fmt.Sprintf("error: %s", err.Error()), err - } - return string(outputBytes), nil -} - -func UninstallDepRemote(nodeId string, lang string, depName string) (err error) { - params := make(map[string]string) - params["lang"] = lang - params["dep_name"] = depName - s := GetService(entity.RpcMessage{ - NodeId: nodeId, - Method: constants.RpcUninstallDep, - Params: params, - Timeout: 300, - }) - _, err = s.ClientHandle() - if err != nil { - return - } - return -} diff --git a/backend/services/schedule.go b/backend/services/schedule.go deleted file mode 100644 index 017fba7d..00000000 --- a/backend/services/schedule.go +++ /dev/null @@ -1,274 +0,0 @@ -package services - -import ( - "crawlab/constants" - "crawlab/lib/cron" - "crawlab/model" - "errors" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - uuid "github.com/satori/go.uuid" - "runtime/debug" -) - -var Sched *Scheduler - -type Scheduler struct { - cron *cron.Cron -} - -func AddScheduleTask(s model.Schedule) func() { - return func() { - // 生成任务ID - id := uuid.NewV4() - - // 参数 - var param string - - // 爬虫 - spider, err := model.GetSpider(s.SpiderId) - if err != nil { - return - } - - // scrapy 爬虫 - if spider.IsScrapy { - if s.ScrapySpider == "" { - log.Errorf("scrapy spider is not set") - debug.PrintStack() - return - } - param = s.ScrapySpider + " -L " + s.ScrapyLogLevel + " " + s.Param - } else { - param = s.Param - } - - if s.RunType == constants.RunTypeAllNodes { - // 所有节点 - nodes, err := model.GetNodeList(nil) - if err != nil { - return - } - for _, node := range nodes { - t := model.Task{ - Id: id.String(), - SpiderId: s.SpiderId, - NodeId: node.Id, - Param: param, - UserId: s.UserId, - RunType: constants.RunTypeAllNodes, - ScheduleId: s.Id, - Type: constants.TaskTypeSpider, - } - - if _, err := AddTask(t); err != nil { - return - } - } - } else if s.RunType == constants.RunTypeRandom { - // 随机 - t := model.Task{ - Id: id.String(), - SpiderId: s.SpiderId, - Param: param, - UserId: s.UserId, - RunType: constants.RunTypeRandom, - ScheduleId: s.Id, - Type: constants.TaskTypeSpider, - } - if _, err := AddTask(t); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - } else if s.RunType == constants.RunTypeSelectedNodes { - // 指定节点 - for _, nodeId := range s.NodeIds { - t := model.Task{ - Id: id.String(), - SpiderId: s.SpiderId, - NodeId: nodeId, - Param: param, - UserId: s.UserId, - RunType: constants.RunTypeSelectedNodes, - ScheduleId: s.Id, - Type: constants.TaskTypeSpider, - } - - if _, err := AddTask(t); err != nil { - return - } - } - } else { - return - } - } -} - -func UpdateSchedules() { - if err := Sched.Update(); err != nil { - log.Errorf(err.Error()) - return - } -} - -func (s *Scheduler) Start() error { - exec := cron.New(cron.WithSeconds()) - - // 启动cron服务 - s.cron.Start() - - // 更新任务列表 - if err := s.Update(); err != nil { - log.Errorf("update scheduler error: %s", err.Error()) - debug.PrintStack() - return err - } - - // 每30秒更新一次任务列表 - spec := "*/30 * * * * *" - if _, err := exec.AddFunc(spec, UpdateSchedules); err != nil { - log.Errorf("add func update schedulers error: %s", err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func (s *Scheduler) AddJob(job model.Schedule) error { - spec := job.Cron - - // 添加定时任务 - eid, err := s.cron.AddFunc(spec, AddScheduleTask(job)) - if err != nil { - log.Errorf("add func task error: %s", err.Error()) - debug.PrintStack() - return err - } - - // 更新EntryID - job.EntryId = eid - - // 更新状态 - job.Status = constants.ScheduleStatusRunning - job.Enabled = true - - // 保存定时任务 - if err := job.Save(); err != nil { - log.Errorf("job save error: %s", err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func (s *Scheduler) RemoveAll() { - entries := s.cron.Entries() - for i := 0; i < len(entries); i++ { - s.cron.Remove(entries[i].ID) - } -} - -// 验证cron表达式是否正确 -func ParserCron(spec string) error { - parser := cron.NewParser( - cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor, - ) - - if _, err := parser.Parse(spec); err != nil { - return err - } - return nil -} - -// 禁用定时任务 -func (s *Scheduler) Disable(id bson.ObjectId) error { - schedule, err := model.GetSchedule(id) - if err != nil { - return err - } - if schedule.EntryId == 0 { - return errors.New("entry id not found") - } - - // 从cron服务中删除该任务 - s.cron.Remove(schedule.EntryId) - - // 更新状态 - schedule.Status = constants.ScheduleStatusStop - schedule.Enabled = false - - if err = schedule.Save(); err != nil { - return err - } - return nil -} - -// 启用定时任务 -func (s *Scheduler) Enable(id bson.ObjectId) error { - schedule, err := model.GetSchedule(id) - if err != nil { - return err - } - if err := s.AddJob(schedule); err != nil { - return err - } - return nil -} - -func (s *Scheduler) Update() error { - // 删除所有定时任务 - s.RemoveAll() - - // 获取所有定时任务 - sList, err := model.GetScheduleList(bson.M{"enabled": true}) - if err != nil { - log.Errorf("get scheduler list error: %s", err.Error()) - debug.PrintStack() - return err - } - - user, err := model.GetUserByUsername("admin") - if err != nil { - log.Errorf("get admin user error: %s", err.Error()) - return err - } - - // 遍历任务列表 - for i := 0; i < len(sList); i++ { - // 单个任务 - job := sList[i] - - if job.Status == constants.ScheduleStatusStop { - continue - } - - // 兼容以前版本 - if job.UserId.Hex() == "" { - job.UserId = user.Id - } - - // 添加到定时任务 - if err := s.AddJob(job); err != nil { - log.Errorf("add job error: %s, job: %s, cron: %s", err.Error(), job.Name, job.Cron) - debug.PrintStack() - return err - } - } - - return nil -} - -func InitScheduler() error { - Sched = &Scheduler{ - cron: cron.New(cron.WithSeconds()), - } - if err := Sched.Start(); err != nil { - log.Errorf("start scheduler error: %s", err.Error()) - debug.PrintStack() - return err - } - return nil -} diff --git a/backend/services/scrapy.go b/backend/services/scrapy.go deleted file mode 100644 index eee7893d..00000000 --- a/backend/services/scrapy.go +++ /dev/null @@ -1,285 +0,0 @@ -package services - -import ( - "bytes" - "crawlab/constants" - "crawlab/entity" - "crawlab/model" - "encoding/json" - "errors" - "fmt" - "github.com/Unknwon/goconfig" - "github.com/apex/log" - "io/ioutil" - "os" - "os/exec" - "path" - "runtime/debug" - "strconv" - "strings" -) - -func GetScrapySpiderNames(s model.Spider) ([]string, error) { - var stdout bytes.Buffer - var stderr bytes.Buffer - - cmd := exec.Command("scrapy", "list") - cmd.Dir = s.Src - cmd.Stdout = &stdout - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return []string{}, errors.New(stderr.String()) - } - - spiderNames := strings.Split(stdout.String(), "\n") - - var res []string - for _, sn := range spiderNames { - if sn != "" { - res = append(res, sn) - } - } - - return res, nil -} - -func GetScrapySettings(s model.Spider) (res []map[string]interface{}, err error) { - var stdout bytes.Buffer - var stderr bytes.Buffer - - cmd := exec.Command("crawlab", "settings") - cmd.Dir = s.Src - cmd.Stdout = &stdout - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - log.Errorf(err.Error()) - log.Errorf(stderr.String()) - debug.PrintStack() - return res, errors.New(stderr.String()) - } - - if err := json.Unmarshal([]byte(stdout.String()), &res); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return res, err - } - - return res, nil -} - -func SaveScrapySettings(s model.Spider, settingsData []entity.ScrapySettingParam) (err error) { - // 读取 scrapy.cfg - cfg, err := goconfig.LoadConfigFile(path.Join(s.Src, "scrapy.cfg")) - if err != nil { - return - } - modName, err := cfg.GetValue("settings", "default") - if err != nil { - return - } - - // 定位到 settings.py 文件 - arr := strings.Split(modName, ".") - dirName := arr[0] - fileName := arr[1] - filePath := fmt.Sprintf("%s/%s/%s.py", s.Src, dirName, fileName) - - // 生成文件内容 - content := "" - for _, param := range settingsData { - var line string - switch param.Type { - case constants.String: - line = fmt.Sprintf("%s = '%s'", param.Key, param.Value) - case constants.Number: - n := int64(param.Value.(float64)) - s := strconv.FormatInt(n, 10) - line = fmt.Sprintf("%s = %s", param.Key, s) - case constants.Boolean: - if param.Value.(bool) { - line = fmt.Sprintf("%s = %s", param.Key, "True") - } else { - line = fmt.Sprintf("%s = %s", param.Key, "False") - } - case constants.Array: - arr := param.Value.([]interface{}) - var arrStr []string - for _, s := range arr { - arrStr = append(arrStr, s.(string)) - } - line = fmt.Sprintf("%s = ['%s']", param.Key, strings.Join(arrStr, "','")) - case constants.Object: - value := param.Value.(map[string]interface{}) - var arr []string - for k, v := range value { - n := int64(v.(float64)) - s := strconv.FormatInt(n, 10) - arr = append(arr, fmt.Sprintf("'%s': %s", k, s)) - } - line = fmt.Sprintf("%s = {%s}", param.Key, strings.Join(arr, ",")) - } - content += line + "\n" - } - - // 写到 settings.py - if err := ioutil.WriteFile(filePath, []byte(content), os.ModePerm); err != nil { - return err - } - - // 同步到GridFS - if err := UploadSpiderToGridFsFromMaster(s); err != nil { - return err - } - - return -} - -func GetScrapyItems(s model.Spider) (res []map[string]interface{}, err error) { - var stdout bytes.Buffer - var stderr bytes.Buffer - - cmd := exec.Command("crawlab", "items") - cmd.Dir = s.Src - cmd.Stdout = &stdout - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - log.Errorf(err.Error()) - log.Errorf(stderr.String()) - debug.PrintStack() - return res, errors.New(stderr.String()) - } - - if err := json.Unmarshal([]byte(stdout.String()), &res); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return res, err - } - - return res, nil -} - -func SaveScrapyItems(s model.Spider, itemsData []entity.ScrapyItem) (err error) { - // 读取 scrapy.cfg - cfg, err := goconfig.LoadConfigFile(path.Join(s.Src, "scrapy.cfg")) - if err != nil { - return - } - modName, err := cfg.GetValue("settings", "default") - if err != nil { - return - } - - // 定位到 settings.py 文件 - arr := strings.Split(modName, ".") - dirName := arr[0] - fileName := "items" - filePath := fmt.Sprintf("%s/%s/%s.py", s.Src, dirName, fileName) - - // 生成文件内容 - content := "" - content += "import scrapy\n" - content += "\n\n" - for _, item := range itemsData { - content += fmt.Sprintf("class %s(scrapy.Item):\n", item.Name) - for _, field := range item.Fields { - content += fmt.Sprintf(" %s = scrapy.Field()\n", field) - } - content += "\n\n" - } - - // 写到 settings.py - if err := ioutil.WriteFile(filePath, []byte(content), os.ModePerm); err != nil { - return err - } - - // 同步到GridFS - if err := UploadSpiderToGridFsFromMaster(s); err != nil { - return err - } - - return -} - -func GetScrapyPipelines(s model.Spider) (res []string, err error) { - var stdout bytes.Buffer - var stderr bytes.Buffer - - cmd := exec.Command("crawlab", "pipelines") - cmd.Dir = s.Src - cmd.Stdout = &stdout - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - log.Errorf(err.Error()) - log.Errorf(stderr.String()) - debug.PrintStack() - return res, errors.New(stderr.String()) - } - - if err := json.Unmarshal([]byte(stdout.String()), &res); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return res, err - } - - return res, nil -} - -func GetScrapySpiderFilepath(s model.Spider, spiderName string) (res string, err error) { - var stdout bytes.Buffer - var stderr bytes.Buffer - - cmd := exec.Command("crawlab", "find_spider_filepath", "-n", spiderName) - cmd.Dir = s.Src - cmd.Stdout = &stdout - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - log.Errorf(err.Error()) - log.Errorf(stderr.String()) - debug.PrintStack() - return res, err - } - - res = strings.Replace(stdout.String(), "\n", "", 1) - - return res, nil -} - -func CreateScrapySpider(s model.Spider, name string, domain string, template string) (err error) { - var stdout bytes.Buffer - var stderr bytes.Buffer - - cmd := exec.Command("scrapy", "genspider", name, domain, "-t", template) - cmd.Dir = s.Src - cmd.Stdout = &stdout - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - log.Errorf(err.Error()) - log.Errorf("stdout: " + stdout.String()) - log.Errorf("stderr: " + stderr.String()) - debug.PrintStack() - return err - } - - return -} - -func CreateScrapyProject(s model.Spider) (err error) { - var stdout bytes.Buffer - var stderr bytes.Buffer - - cmd := exec.Command("scrapy", "startproject", s.Name, s.Src) - cmd.Dir = s.Src - cmd.Stdout = &stdout - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - log.Errorf(err.Error()) - log.Errorf("stdout: " + stdout.String()) - log.Errorf("stderr: " + stderr.String()) - debug.PrintStack() - return err - } - - return -} diff --git a/backend/services/spider.go b/backend/services/spider.go deleted file mode 100644 index 59aa1fad..00000000 --- a/backend/services/spider.go +++ /dev/null @@ -1,624 +0,0 @@ -package services - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/entity" - "crawlab/lib/cron" - "crawlab/model" - "crawlab/services/spider_handler" - "crawlab/utils" - "errors" - "fmt" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "github.com/satori/go.uuid" - "github.com/spf13/viper" - "gopkg.in/yaml.v2" - "io" - "io/ioutil" - "os" - "path" - "path/filepath" - "runtime/debug" - "time" -) - -type SpiderFileData struct { - FileName string - File []byte -} - -type SpiderUploadMessage struct { - FileId string - FileName string - SpiderId string -} - -// 从主节点上传爬虫到GridFS -func UploadSpiderToGridFsFromMaster(spider model.Spider) error { - // 爬虫所在目录 - spiderDir := spider.Src - - // 打包为 zip 文件 - files, err := utils.GetFilesFromDir(spiderDir) - if err != nil { - return err - } - randomId := uuid.NewV4() - tmpFilePath := filepath.Join(viper.GetString("other.tmppath"), spider.Name+"."+randomId.String()+".zip") - spiderZipFileName := spider.Name + ".zip" - if err := utils.Compress(files, tmpFilePath); err != nil { - return err - } - - // 获取 GridFS 实例 - s, gf := database.GetGridFs("files") - defer s.Close() - - // 判断文件是否已经存在 - var gfFile model.GridFs - if err := gf.Find(bson.M{"filename": spiderZipFileName}).One(&gfFile); err == nil { - // 已经存在文件,则删除 - log.Errorf(gfFile.Id.Hex() + " already exists. removing...") - if err := gf.RemoveId(gfFile.Id); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - } - - // 上传到GridFs - fid, err := RetryUploadToGridFs(spiderZipFileName, tmpFilePath) - if err != nil { - log.Errorf("upload to grid fs error: %s", err.Error()) - } - - // 保存爬虫 FileId - spider.FileId = fid - if err := spider.Save(); err != nil { - return err - } - - // 获取爬虫同步实例 - spiderSync := spider_handler.SpiderSync{ - Spider: spider, - } - - // 获取gfFile - gfFile2 := model.GetGridFs(spider.FileId) - - // 生成MD5 - spiderSync.CreateMd5File(gfFile2.Md5) - - // 检查是否为 Scrapy 爬虫 - spiderSync.CheckIsScrapy() - - return nil -} - -// 上传zip文件到GridFS -func UploadToGridFs(fileName string, filePath string) (fid bson.ObjectId, err error) { - fid = "" - - // 获取MongoDB GridFS连接 - s, gf := database.GetGridFs("files") - defer s.Close() - - // 创建一个新GridFS文件 - f, err := gf.Create(fileName) - if err != nil { - log.Errorf("create file error: " + err.Error()) - debug.PrintStack() - return - } - - // 分片读取爬虫zip文件 - err = ReadFileByStep(filePath, WriteToGridFS, f) - if err != nil { - log.Errorf("read file by step error: " + err.Error()) - debug.PrintStack() - return "", err - } - - // 删除zip文件 - if err = os.Remove(filePath); err != nil { - log.Errorf("remove file error: " + err.Error()) - debug.PrintStack() - return - } - - // 关闭文件,提交写入 - if err = f.Close(); err != nil { - log.Errorf("close file error: " + err.Error()) - debug.PrintStack() - return "", err - } - - // 文件ID - fid = f.Id().(bson.ObjectId) - - return fid, nil -} - -// 带重试功能的上传至 GridFS -func RetryUploadToGridFs(fileName string, filePath string) (fid bson.ObjectId, err error) { - maxErrCount := 10 - errCount := 0 - for { - if errCount > maxErrCount { - break - } - fid, err = UploadToGridFs(fileName, filePath) - if err != nil { - errCount++ - log.Errorf("upload to grid fs error: %s", err.Error()) - time.Sleep(3 * time.Second) - continue - } - return fid, nil - } - return fid, errors.New("unable to upload to gridfs, please re-upload the spider") -} - -// 写入grid fs -func WriteToGridFS(content []byte, f *mgo.GridFile) { - if _, err := f.Write(content); err != nil { - debug.PrintStack() - return - } -} - -//分片读取大文件 -func ReadFileByStep(filePath string, handle func([]byte, *mgo.GridFile), fileCreate *mgo.GridFile) error { - f, err := os.OpenFile(filePath, os.O_RDONLY, 0777) - if err != nil { - log.Infof("can't opened this file") - return err - } - defer utils.Close(f) - s := make([]byte, 4096) - for { - switch nr, err := f.Read(s[:]); true { - case nr < 0: - _, _ = fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error()) - debug.PrintStack() - case nr == 0: // EOF - return nil - case nr > 0: - handle(s[0:nr], fileCreate) - } - } -} - -// 发布所有爬虫 -func PublishAllSpiders() { - // 获取爬虫列表 - spiders, _, _ := model.GetSpiderList(nil, 0, constants.Infinite, "-_id") - if len(spiders) == 0 { - return - } - log.Infof("start sync spider to local, total: %d", len(spiders)) - // 遍历爬虫列表 - for _, spider := range spiders { - // 异步发布爬虫 - go func(s model.Spider) { - PublishSpider(s) - }(spider) - } -} - -// 发布爬虫 -func PublishSpider(spider model.Spider) { - var gfFile *model.GridFs - if spider.FileId.Hex() != constants.ObjectIdNull { - // 查询gf file,不存在则标记为爬虫文件不存在 - gfFile = model.GetGridFs(spider.FileId) - if gfFile == nil { - log.Errorf("get grid fs file error: cannot find grid fs file") - log.Errorf("grid fs file_id: " + spider.FileId.Hex()) - log.Errorf("spider_name: " + spider.Name) - debug.PrintStack() - //spider.FileId = constants.ObjectIdNull - //if err := spider.Save(); err != nil { - // return - //} - return - } - } - - // 如果FileId为空,表示还没有上传爬虫到GridFS,则跳过 - if spider.FileId == bson.ObjectIdHex(constants.ObjectIdNull) { - return - } - - // 获取爬虫同步实例 - spiderSync := spider_handler.SpiderSync{ - Spider: spider, - } - - // 安装依赖 - if viper.GetString("setting.autoInstall") == "Y" { - go spiderSync.InstallDeps() - } - - //目录不存在,则直接下载 - path := filepath.Join(viper.GetString("spider.path"), spider.Name) - if !utils.Exists(path) { - log.Infof("path not found: %s", path) - spiderSync.Download() - spiderSync.CreateMd5File(gfFile.Md5) - spiderSync.CheckIsScrapy() - return - } - - // md5文件不存在,则下载 - md5 := filepath.Join(path, spider_handler.Md5File) - if !utils.Exists(md5) { - log.Infof("md5 file not found: %s", md5) - spiderSync.RemoveDownCreate(gfFile.Md5) - return - } - - // md5值不一样,则下载 - md5Str := utils.GetSpiderMd5Str(md5) - if gfFile.Md5 != md5Str { - log.Infof("md5 is different, gf-md5:%s, file-md5:%s", gfFile.Md5, md5Str) - spiderSync.RemoveDownCreate(gfFile.Md5) - return - } -} - -func RemoveSpider(id string) error { - // 获取该爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - return err - } - - // 删除爬虫文件目录 - path := filepath.Join(viper.GetString("spider.path"), spider.Name) - utils.RemoveFiles(path) - - // 删除其他节点的爬虫目录 - //msg := entity.NodeMessage{ - // Type: constants.MsgTypeRemoveSpider, - // SpiderId: id, - //} - //if err := database.Pub(constants.ChannelAllNode, msg); err != nil { - // return err - //} - - // 从数据库中删除该爬虫 - if err := model.RemoveSpider(bson.ObjectIdHex(id)); err != nil { - return err - } - - // 删除日志文件 - if err := RemoveLogBySpiderId(spider.Id); err != nil { - return err - } - - // 删除爬虫对应的task任务 - if err := model.RemoveTaskBySpiderId(spider.Id); err != nil { - return err - } - - // TODO 定时任务如何处理 - return nil -} - -func CancelSpider(id string) error { - // 获取该爬虫 - spider, err := model.GetSpider(bson.ObjectIdHex(id)) - if err != nil { - return err - } - - // 获取该爬虫待定或运行中的任务列表 - query := bson.M{ - "spider_id": spider.Id, - "status": bson.M{ - "$in": []string{ - constants.StatusPending, - constants.StatusRunning, - }, - }, - } - tasks, err := model.GetTaskList(query, 0, constants.Infinite, "-create_ts") - if err != nil { - return err - } - - // 遍历任务列表,依次停止 - for _, task := range tasks { - if err := CancelTask(task.Id); err != nil { - return err - } - } - - return nil -} - -func cloneGridFsFile(spider model.Spider, newName string) (err error) { - // 构造新爬虫 - newSpider := spider - newSpider.Id = bson.NewObjectId() - newSpider.Name = newName - newSpider.DisplayName = newName - newSpider.Src = path.Join(path.Dir(spider.Src), newName) - newSpider.CreateTs = time.Now() - newSpider.UpdateTs = time.Now() - - // GridFS连接实例 - s, gf := database.GetGridFs("files") - defer s.Close() - - // 被克隆爬虫的GridFS文件 - f, err := gf.OpenId(spider.FileId) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 新爬虫的GridFS文件 - fNew, err := gf.Create(newSpider.Name + ".zip") - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 生成唯一ID - randomId := uuid.NewV4() - tmpPath := viper.GetString("other.tmppath") - if !utils.Exists(tmpPath) { - if err := os.MkdirAll(tmpPath, 0777); err != nil { - log.Errorf("mkdir other.tmppath error: %v", err.Error()) - return err - } - } - - // 创建临时文件 - tmpFilePath := filepath.Join(tmpPath, randomId.String()+".zip") - tmpFile := utils.OpenFile(tmpFilePath) - - // 拷贝到临时文件 - if _, err := io.Copy(tmpFile, f); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 关闭临时文件 - if err := tmpFile.Close(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 读取内容 - fContent, err := ioutil.ReadFile(tmpFilePath) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 写入GridFS文件 - if _, err := fNew.Write(fContent); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 关闭被克隆爬虫GridFS文件 - if err = f.Close(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 将新爬虫文件复制 - newSpider.FileId = fNew.Id().(bson.ObjectId) - - // 保存新爬虫 - if err := newSpider.Add(); err != nil { - return err - } - - // 关闭新爬虫GridFS文件 - if err := fNew.Close(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 删除临时文件 - if err := os.RemoveAll(tmpFilePath); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - // 同步爬虫 - PublishSpider(newSpider) - - return nil -} - -func CopySpider(spider model.Spider, newName string) error { - // 克隆GridFS文件 - if err := cloneGridFsFile(spider, newName); err != nil { - return err - } - - return nil -} - -func UpdateSpiderDedup(spider model.Spider) error { - col := utils.GetSpiderCol(spider.Col, spider.Name) - - s, c := database.GetCol(col) - defer s.Close() - - if !spider.IsDedup { - _ = c.DropIndex(spider.DedupField) - //if err := c.DropIndex(spider.DedupField); err != nil { - // return err - //} - return nil - } - - if err := c.EnsureIndex(mgo.Index{ - Key: []string{spider.DedupField}, - Unique: true, - }); err != nil { - return err - } - - return nil -} - -func InitDemoSpiders() { - // 添加Demo爬虫 - templateSpidersDir := "./template/spiders" - for _, info := range utils.ListDir(templateSpidersDir) { - if !info.IsDir() { - continue - } - spiderName := info.Name() - - // 如果爬虫在数据库中不存在,则添加 - spider := model.GetSpiderByName(spiderName) - if spider.Name != "" { - // 存在同名爬虫,跳过 - continue - } - - // 拷贝爬虫 - templateSpiderPath := path.Join(templateSpidersDir, spiderName) - spiderPath := path.Join(viper.GetString("spider.path"), spiderName) - if utils.Exists(spiderPath) { - utils.RemoveFiles(spiderPath) - } - if err := utils.CopyDir(templateSpiderPath, spiderPath); err != nil { - log.Errorf("copy error: " + err.Error()) - debug.PrintStack() - continue - } - - // 构造配置数据 - configData := entity.ConfigSpiderData{} - - // 读取YAML文件 - yamlFile, err := ioutil.ReadFile(path.Join(spiderPath, "Spiderfile")) - if err != nil { - log.Errorf("read yaml error: " + err.Error()) - //debug.PrintStack() - continue - } - - // 反序列化 - if err := yaml.Unmarshal(yamlFile, &configData); err != nil { - log.Errorf("unmarshal error: " + err.Error()) - debug.PrintStack() - continue - } - - if configData.Type == constants.Customized { - // 添加该爬虫到数据库 - spider = model.Spider{ - Id: bson.NewObjectId(), - Name: spiderName, - DisplayName: configData.DisplayName, - Type: constants.Customized, - Col: configData.Col, - Src: spiderPath, - Remark: configData.Remark, - ProjectId: bson.ObjectIdHex(constants.ObjectIdNull), - FileId: bson.ObjectIdHex(constants.ObjectIdNull), - Cmd: configData.Cmd, - UserId: bson.ObjectIdHex(constants.ObjectIdNull), - } - if err := spider.Add(); err != nil { - log.Errorf("add spider error: " + err.Error()) - debug.PrintStack() - continue - } - - // 上传爬虫到GridFS - if err := UploadSpiderToGridFsFromMaster(spider); err != nil { - log.Errorf("upload spider error: " + err.Error()) - debug.PrintStack() - continue - } - } else if configData.Type == constants.Configurable || configData.Type == "config" { - // 添加该爬虫到数据库 - spider = model.Spider{ - Id: bson.NewObjectId(), - Name: configData.Name, - DisplayName: configData.DisplayName, - Type: constants.Configurable, - Col: configData.Col, - Src: spiderPath, - Remark: configData.Remark, - ProjectId: bson.ObjectIdHex(constants.ObjectIdNull), - FileId: bson.ObjectIdHex(constants.ObjectIdNull), - Config: configData, - UserId: bson.ObjectIdHex(constants.ObjectIdNull), - } - if err := spider.Add(); err != nil { - log.Errorf("add spider error: " + err.Error()) - debug.PrintStack() - continue - } - - // 根据序列化后的数据处理爬虫文件 - if err := ProcessSpiderFilesFromConfigData(spider, configData); err != nil { - log.Errorf("add spider error: " + err.Error()) - debug.PrintStack() - continue - } - } - } - - // 发布所有爬虫 - PublishAllSpiders() -} - -// 启动爬虫服务 -func InitSpiderService() error { - // 构造定时任务执行器 - cPub := cron.New(cron.WithSeconds()) - if _, err := cPub.AddFunc("0 * * * * *", PublishAllSpiders); err != nil { - return err - } - - // 启动定时任务 - cPub.Start() - - if model.IsMaster() && viper.GetString("setting.demoSpiders") == "Y" { - // 初始化Demo爬虫 - InitDemoSpiders() - } - - if model.IsMaster() { - // 构造 Git 定时任务 - GitCron = &GitCronScheduler{ - cron: cron.New(cron.WithSeconds()), - } - - // 启动 Git 定时任务 - if err := GitCron.Start(); err != nil { - return err - } - - // 清理UserId - InitSpiderCleanUserIds() - } - - return nil -} diff --git a/backend/services/spider_handler/spider.go b/backend/services/spider_handler/spider.go deleted file mode 100644 index 389ea6cd..00000000 --- a/backend/services/spider_handler/spider.go +++ /dev/null @@ -1,250 +0,0 @@ -package spider_handler - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/model" - "crawlab/services/local_node" - "crawlab/utils" - "fmt" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "github.com/satori/go.uuid" - "github.com/spf13/viper" - "io" - "os" - "os/exec" - "path" - "path/filepath" - "runtime/debug" - "strings" - "sync" -) - -const ( - Md5File = "md5.txt" -) - -type SpiderSync struct { - Spider model.Spider -} - -func (s *SpiderSync) CreateMd5File(md5 string) { - path := filepath.Join(viper.GetString("spider.path"), s.Spider.Name) - utils.CreateDirPath(path) - - fileName := filepath.Join(path, Md5File) - file := utils.OpenFile(fileName) - defer utils.Close(file) - if file != nil { - if _, err := file.WriteString(md5 + "\n"); err != nil { - log.Errorf("file write string error: %s", err.Error()) - debug.PrintStack() - } - } -} - -func (s *SpiderSync) CheckIsScrapy() { - if s.Spider.Type == constants.Configurable { - return - } - if viper.GetString("setting.checkScrapy") != "Y" { - return - } - s.Spider.IsScrapy = utils.Exists(path.Join(s.Spider.Src, "scrapy.cfg")) - if s.Spider.IsScrapy { - s.Spider.Cmd = "scrapy crawl" - } - if err := s.Spider.Save(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } -} - -func (s *SpiderSync) AfterRemoveDownCreate() { - if model.IsMaster() { - s.CheckIsScrapy() - } -} - -func (s *SpiderSync) RemoveDownCreate(md5 string) { - s.RemoveSpiderFile() - s.Download() - s.CreateMd5File(md5) - s.AfterRemoveDownCreate() -} - -// 获得下载锁的key -func (s *SpiderSync) GetLockDownloadKey(spiderId string) string { - //node, _ := model.GetCurrentNode() - node := local_node.CurrentNode() - - return node.Id.Hex() + "#" + spiderId -} - -// 删除本地文件 -func (s *SpiderSync) RemoveSpiderFile() { - path := filepath.Join( - viper.GetString("spider.path"), - s.Spider.Name, - ) - //爬虫文件有变化,先删除本地文件 - if err := os.RemoveAll(path); err != nil { - log.Errorf("remove spider files error: %s, path: %s", err.Error(), path) - debug.PrintStack() - } -} - -// 检测是否已经下载中 -func (s *SpiderSync) CheckDownLoading(spiderId string, fileId string) (bool, string) { - key := s.GetLockDownloadKey(spiderId) - key2, err := database.RedisClient.HGet("spider", key) - if err != nil { - return false, key2 - } - if key2 == "" { - return false, key2 - } - return true, key2 -} - -// 下载爬虫 -func (s *SpiderSync) Download() { - spiderId := s.Spider.Id.Hex() - fileId := s.Spider.FileId.Hex() - isDownloading, key := s.CheckDownLoading(spiderId, fileId) - if isDownloading { - log.Infof(fmt.Sprintf("spider is already being downloaded, spider id: %s", s.Spider.Id.Hex())) - return - } else { - _ = database.RedisClient.HSet("spider", key, key) - } - - session, gf := database.GetGridFs("files") - defer session.Close() - - f, err := gf.OpenId(bson.ObjectIdHex(fileId)) - defer utils.Close(f) - if err != nil { - log.Errorf("open file id: " + fileId + ", spider id:" + spiderId + ", error: " + err.Error()) - debug.PrintStack() - return - } - - // 生成唯一ID - randomId := uuid.NewV4() - tmpPath := viper.GetString("other.tmppath") - if !utils.Exists(tmpPath) { - if err := os.MkdirAll(tmpPath, 0777); err != nil { - log.Errorf("mkdir other.tmppath error: %v", err.Error()) - return - } - } - // 创建临时文件 - tmpFilePath := filepath.Join(tmpPath, randomId.String()+".zip") - tmpFile := utils.OpenFile(tmpFilePath) - - // 将该文件写入临时文件 - if _, err := io.Copy(tmpFile, f); err != nil { - log.Errorf("copy file error: %s, file_id: %s", err.Error(), f.Id()) - debug.PrintStack() - return - } - - // 解压缩临时文件到目标文件夹 - dstPath := filepath.Join( - viper.GetString("spider.path"), - s.Spider.Name, - ) - if err := utils.DeCompress(tmpFile, dstPath); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - - //递归修改目标文件夹权限 - // 解决scrapy.setting中开启LOG_ENABLED 和 LOG_FILE时不能创建log文件的问题 - cmd := exec.Command("chmod", "-R", "777", dstPath) - if err := cmd.Run(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - - // 关闭临时文件 - if err := tmpFile.Close(); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - - // 删除临时文件 - if err := os.Remove(tmpFilePath); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - - _ = database.RedisClient.HDel("spider", key) -} - -// locks for dependency installation -var installLockMap sync.Map - -// install dependencies -func (s *SpiderSync) InstallDeps() { - langs := utils.GetLangList() - for _, l := range langs { - // no dep file name is found, skip - if l.DepFileName == "" { - continue - } - - // being locked, i.e. installation is running, skip - key := s.Spider.Name + "|" + l.Name - _, locked := installLockMap.Load(key) - if locked { - continue - } - - // no dep file found, skip - if !utils.Exists(path.Join(s.Spider.Src, l.DepFileName)) { - continue - } - - // no dep install executable found, skip - if !utils.Exists(l.DepExecutablePath) { - continue - } - - // lock - installLockMap.Store(key, true) - - // command to install dependencies - cmd := exec.Command(l.DepExecutablePath, strings.Split(l.InstallDepArgs, " ")...) - - // working directory - cmd.Dir = s.Spider.Src - - // compatibility with node.js - if l.ExecutableName == constants.Nodejs { - deps, err := utils.GetPackageJsonDeps(path.Join(s.Spider.Src, l.DepFileName)) - if err != nil { - continue - } - cmd = exec.Command(l.DepExecutablePath, strings.Split(l.InstallDepArgs+" "+strings.Join(deps, " "), " ")...) - } - - // start executing command - output, err := cmd.Output() - if err != nil { - log.Errorf("install dep error: " + err.Error()) - log.Errorf(string(output)) - debug.PrintStack() - } - - // unlock - installLockMap.Delete(key) - } -} diff --git a/backend/services/spider_handler/spider_test.go b/backend/services/spider_handler/spider_test.go deleted file mode 100644 index 66d47455..00000000 --- a/backend/services/spider_handler/spider_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package spider_handler - -import ( - "crawlab/config" - "crawlab/database" - "crawlab/model" - "github.com/apex/log" - "github.com/globalsign/mgo/bson" - "runtime/debug" - "testing" -) - -var s SpiderSync - -func init() { - if err := config.InitConfig("../../conf/config.yml"); err != nil { - log.Fatal("Init config failed") - } - log.Infof("初始化配置成功") - - // 初始化Mongodb数据库 - if err := database.InitMongo(); err != nil { - log.Error("init mongodb error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("初始化Mongodb数据库成功") - - // 初始化Redis数据库 - if err := database.InitRedis(); err != nil { - log.Error("init redis error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("初始化Redis数据库成功") - - s = SpiderSync{ - Spider: model.Spider{ - Id: bson.ObjectIdHex("5d8d8326bc3c4f000186e5df"), - Name: "scrapy-pre_sale", - FileId: bson.ObjectIdHex("5d8d8326bc3c4f000186e5db"), - Src: "/opt/crawlab/spiders/scrapy-pre_sale", - }, - } -} - -func TestSpiderSync_CreateMd5File(t *testing.T) { - s.CreateMd5File("this is md5") -} - -func TestSpiderSync_Download(t *testing.T) { - s.Download() -} diff --git a/backend/services/sys_exec/linux_mac.go b/backend/services/sys_exec/linux_mac.go deleted file mode 100644 index 394dce47..00000000 --- a/backend/services/sys_exec/linux_mac.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build !windows - -package sys_exec - -import ( - "os/exec" - "syscall" -) - -func BuildCmd(cmdStr string) *exec.Cmd { - return exec.Command("sh", "-c", cmdStr) -} - -func Setpgid(cmd *exec.Cmd) { - if cmd == nil { - return - } - if cmd.SysProcAttr == nil { - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - } else { - cmd.SysProcAttr.Setpgid = true - } -} - -func KillProcess(cmd *exec.Cmd) error { - if cmd == nil { - return nil - } - return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) -} diff --git a/backend/services/sys_exec/windows.go b/backend/services/sys_exec/windows.go deleted file mode 100644 index 63199b09..00000000 --- a/backend/services/sys_exec/windows.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build windows - -package sys_exec - -import ( - "os/exec" -) - -func BuildCmd(cmdStr string) *exec.Cmd { - return exec.Command("cmd", "/C", cmdStr) -} - -func Setpgid(cmd *exec.Cmd) { - return -} - -func KillProcess(cmd *exec.Cmd) error { - if cmd != nil && cmd.Process != nil { - if err := cmd.Process.Kill(); err != nil { - return err - } - } - return nil -} diff --git a/backend/services/system.go b/backend/services/system.go deleted file mode 100644 index a4b19e98..00000000 --- a/backend/services/system.go +++ /dev/null @@ -1,393 +0,0 @@ -package services - -import ( - "crawlab/constants" - "crawlab/database" - "crawlab/entity" - "crawlab/lib/cron" - "crawlab/model" - "crawlab/services/rpc" - "crawlab/utils" - "encoding/json" - "errors" - "fmt" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "github.com/imroc/req" - "os/exec" - "regexp" - "runtime/debug" - "sort" - "strings" - "sync" -) - -// 系统信息 chan 映射 -var SystemInfoChanMap = utils.NewChanMap() - -// 从远端获取系统信息 -func GetRemoteSystemInfo(nodeId string) (sysInfo entity.SystemInfo, err error) { - // 发送消息 - msg := entity.NodeMessage{ - Type: constants.MsgTypeGetSystemInfo, - NodeId: nodeId, - } - - // 序列化 - msgBytes, _ := json.Marshal(&msg) - if _, err := database.RedisClient.Publish("nodes:"+nodeId, utils.BytesToString(msgBytes)); err != nil { - return entity.SystemInfo{}, err - } - - // 通道 - ch := SystemInfoChanMap.ChanBlocked(nodeId) - - // 等待响应,阻塞 - sysInfoStr := <-ch - - // 反序列化 - if err := json.Unmarshal([]byte(sysInfoStr), &sysInfo); err != nil { - return sysInfo, err - } - - return sysInfo, nil -} - -// 获取系统信息 -func GetSystemInfo(nodeId string) (sysInfo entity.SystemInfo, err error) { - if IsMasterNode(nodeId) { - sysInfo, err = rpc.GetSystemInfoServiceLocal() - } else { - sysInfo, err = rpc.GetSystemInfoServiceRemote(nodeId) - } - return -} - -// 获取语言列表 -func GetLangList(nodeId string) []entity.Lang { - list := utils.GetLangList() - for i, lang := range list { - status, _ := GetLangInstallStatus(nodeId, lang) - list[i].InstallStatus = status - } - return list -} - -// 获取语言安装状态 -func GetLangInstallStatus(nodeId string, lang entity.Lang) (string, error) { - _, err := model.GetTaskByFilter(bson.M{ - "node_id": nodeId, - "cmd": fmt.Sprintf("sh %s", utils.GetSystemScriptPath(lang.InstallScript)), - "status": bson.M{ - "$in": []string{constants.StatusPending, constants.StatusRunning}, - }, - }) - if err == nil { - // 任务正在运行,正在安装 - return constants.InstallStatusInstalling, nil - } - if err != mgo.ErrNotFound { - // 发生错误 - return "", err - } - // 获取状态 - if IsMasterNode(nodeId) { - lang := rpc.GetLangLocal(lang) - return lang.InstallStatus, nil - } else { - lang, err := rpc.GetLangRemote(nodeId, lang) - if err != nil { - return "", err - } - return lang.InstallStatus, nil - } -} - -// 是否已安装该依赖 -func IsInstalledDep(installedDepList []entity.Dependency, dep entity.Dependency) bool { - for _, _dep := range installedDepList { - if strings.ToLower(_dep.Name) == strings.ToLower(dep.Name) { - return true - } - } - return false -} - -// ========Python======== - -// 初始化函数 -func InitDepsFetcher() error { - c := cron.New(cron.WithSeconds()) - c.Start() - if _, err := c.AddFunc("0 */5 * * * *", UpdatePythonDepList); err != nil { - return err - } - - go func() { - UpdatePythonDepList() - }() - return nil -} - -type PythonDepJsonData struct { - Info PythonDepJsonDataInfo `json:"info"` -} - -type PythonDepJsonDataInfo struct { - Name string `json:"name"` - Summary string `json:"summary"` - Version string `json:"version"` -} - -type PythonDepNameDict struct { - Name string `json:"name"` - Weight int `json:"weight"` -} - -type PythonDepNameDictSlice []PythonDepNameDict - -func (s PythonDepNameDictSlice) Len() int { return len(s) } -func (s PythonDepNameDictSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s PythonDepNameDictSlice) Less(i, j int) bool { return s[i].Weight > s[j].Weight } - -// 获取Python本地依赖列表 -func GetPythonDepList(nodeId string, searchDepName string) ([]entity.Dependency, error) { - var list []entity.Dependency - - // 先从 Redis 获取 - depList, err := GetPythonDepListFromRedis() - if err != nil { - return list, err - } - - // 过滤相似的依赖 - var depNameList PythonDepNameDictSlice - for _, depName := range depList { - if strings.HasPrefix(strings.ToLower(depName), strings.ToLower(searchDepName)) { - var weight int - if strings.ToLower(depName) == strings.ToLower(searchDepName) { - weight = 3 - } else if strings.HasPrefix(strings.ToLower(depName), strings.ToLower(searchDepName)) { - weight = 2 - } else { - weight = 1 - } - depNameList = append(depNameList, PythonDepNameDict{ - Name: depName, - Weight: weight, - }) - } - } - - // 获取已安装依赖列表 - var installedDepList []entity.Dependency - if IsMasterNode(nodeId) { - installedDepList, err = rpc.GetInstalledDepsLocal(constants.Python) - if err != nil { - return list, err - } - } else { - installedDepList, err = rpc.GetInstalledDepsRemote(nodeId, constants.Python) - if err != nil { - return list, err - } - } - - // 根据依赖名排序 - sort.Stable(depNameList) - - // 遍历依赖名列表,取前20个 - for i, depNameDict := range depNameList { - if i > 20 { - break - } - dep := entity.Dependency{ - Name: depNameDict.Name, - } - dep.Installed = IsInstalledDep(installedDepList, dep) - list = append(list, dep) - } - - // 从依赖源获取信息 - //list, err = GetPythonDepListWithInfo(list) - - return list, nil -} - -// 获取Python依赖的源数据信息 -func GetPythonDepListWithInfo(depList []entity.Dependency) ([]entity.Dependency, error) { - var goSync sync.WaitGroup - for i, dep := range depList { - if i > 10 { - break - } - goSync.Add(1) - go func(i int, dep entity.Dependency, depList []entity.Dependency, n *sync.WaitGroup) { - url := fmt.Sprintf("https://pypi.org/pypi/%s/json", dep.Name) - res, err := req.Get(url) - if err != nil { - n.Done() - return - } - var data PythonDepJsonData - if err := res.ToJSON(&data); err != nil { - n.Done() - return - } - depList[i].Version = data.Info.Version - depList[i].Description = data.Info.Summary - n.Done() - }(i, dep, depList, &goSync) - } - goSync.Wait() - return depList, nil -} - -func FetchPythonDepInfo(depName string) (entity.Dependency, error) { - url := fmt.Sprintf("https://pypi.org/pypi/%s/json", depName) - res, err := req.Get(url) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return entity.Dependency{}, err - } - var data PythonDepJsonData - if res.Response().StatusCode == 404 { - return entity.Dependency{}, errors.New("get depName from [https://pypi.org] error: 404") - } - if err := res.ToJSON(&data); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return entity.Dependency{}, err - } - dep := entity.Dependency{ - Name: depName, - Version: data.Info.Version, - Description: data.Info.Summary, - } - return dep, nil -} - -// 从Redis获取Python依赖列表 -func GetPythonDepListFromRedis() ([]string, error) { - var list []string - - // 从 Redis 获取字符串 - rawData, err := database.RedisClient.HGet("system", "deps:python") - if err != nil { - return list, err - } - - // 反序列化 - if err := json.Unmarshal([]byte(rawData), &list); err != nil { - return list, err - } - - // 如果为空,则从依赖源获取列表 - if len(list) == 0 { - UpdatePythonDepList() - } - - return list, nil -} - -// 从Python依赖源获取依赖列表并返回 -func FetchPythonDepList() ([]string, error) { - // 依赖URL - url := "https://pypi.tuna.tsinghua.edu.cn/simple" - - // 输出列表 - var list []string - - // 请求URL - res, err := req.Get(url) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return list, err - } - - // 获取响应数据 - text, err := res.ToString() - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return list, err - } - - // 从响应数据中提取依赖名 - regex := regexp.MustCompile("(.*)") - for _, line := range strings.Split(text, "\n") { - arr := regex.FindStringSubmatch(line) - if len(arr) < 2 { - continue - } - list = append(list, arr[1]) - } - - // 赋值给列表 - return list, nil -} - -// 更新Python依赖列表到Redis -func UpdatePythonDepList() { - // 从依赖源获取列表 - list, _ := FetchPythonDepList() - - // 序列化 - listBytes, err := json.Marshal(list) - if err != nil { - log.Error(err.Error()) - debug.PrintStack() - return - } - - // 设置Redis - if err := database.RedisClient.HSet("system", "deps:python", string(listBytes)); err != nil { - log.Error(err.Error()) - debug.PrintStack() - return - } -} - -// ========./Python======== - -// ========Node.js======== - -// 获取Nodejs本地依赖列表 -func GetNodejsDepList(nodeId string, searchDepName string) (depList []entity.Dependency, err error) { - // 执行shell命令 - cmd := exec.Command("npm", "search", "--json", searchDepName) - outputBytes, _ := cmd.Output() - - // 获取已安装依赖列表 - var installedDepList []entity.Dependency - if IsMasterNode(nodeId) { - installedDepList, err = rpc.GetInstalledDepsLocal(constants.Nodejs) - if err != nil { - return depList, err - } - } else { - installedDepList, err = rpc.GetInstalledDepsRemote(nodeId, constants.Nodejs) - if err != nil { - return depList, err - } - } - - // 反序列化 - if err := json.Unmarshal(outputBytes, &depList); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return depList, err - } - - // 遍历安装列表 - for i, dep := range depList { - depList[i].Installed = IsInstalledDep(installedDepList, dep) - } - - return depList, nil -} - -// ========./Node.js======== diff --git a/backend/services/task.go b/backend/services/task.go deleted file mode 100644 index 78eb576a..00000000 --- a/backend/services/task.go +++ /dev/null @@ -1,1051 +0,0 @@ -package services - -import ( - "bufio" - "crawlab/constants" - "crawlab/database" - "crawlab/lib/cron" - "crawlab/model" - "crawlab/services/local_node" - "crawlab/services/notification" - "crawlab/services/rpc" - "crawlab/services/spider_handler" - "crawlab/services/sys_exec" - "crawlab/utils" - "encoding/json" - "errors" - "fmt" - "github.com/apex/log" - "github.com/globalsign/mgo" - "github.com/globalsign/mgo/bson" - "github.com/imroc/req" - "github.com/satori/go.uuid" - "github.com/spf13/viper" - "net/http" - "os" - "os/exec" - "path/filepath" - "runtime/debug" - "strconv" - "strings" - "sync" - "time" -) - -var Exec *Executor - -// 任务执行锁 -//Added by cloud: 2019/09/04,solve data race -var LockList sync.Map - -// 任务消息 -type TaskMessage struct { - Id string - Cmd string -} - -// 序列化任务消息 -func (m *TaskMessage) ToString() (string, error) { - data, err := json.Marshal(&m) - if err != nil { - return "", err - } - return utils.BytesToString(data), err -} - -// 任务执行器 -type Executor struct { - Cron *cron.Cron -} - -// 启动任务执行器 -func (ex *Executor) Start() error { - // 启动cron服务 - ex.Cron.Start() - - // 加入执行器到定时任务 - spec := "0/1 * * * * *" // 每秒执行一次 - for i := 0; i < viper.GetInt("task.workers"); i++ { - // WorkerID - id := i - - // 初始化任务锁 - LockList.Store(id, false) - - // 加入定时任务 - _, err := ex.Cron.AddFunc(spec, GetExecuteTaskFunc(id)) - if err != nil { - return err - } - } - - return nil -} - -// 派发任务 -func AssignTask(task model.Task) error { - // 生成任务信息 - msg := TaskMessage{ - Id: task.Id, - } - - // 序列化 - msgStr, err := msg.ToString() - if err != nil { - return err - } - - // 队列名称 - var queue string - if utils.IsObjectIdNull(task.NodeId) { - queue = "tasks:public" - } else { - queue = "tasks:node:" + task.NodeId.Hex() - } - - // 任务入队 - if err := database.RedisClient.RPush(queue, msgStr); err != nil { - return err - } - return nil -} - -// 设置环境变量 -func SetEnv(cmd *exec.Cmd, envs []model.Env, task model.Task, spider model.Spider) *exec.Cmd { - // 默认把Node.js的全局node_modules加入环境变量 - envPath := os.Getenv("PATH") - nodePath := "/usr/lib/node_modules" - if !strings.Contains(envPath, nodePath) { - _ = os.Setenv("PATH", nodePath+":"+envPath) - } - _ = os.Setenv("NODE_PATH", nodePath) - - // default results collection - col := utils.GetSpiderCol(spider.Col, spider.Name) - - // 默认环境变量 - cmd.Env = append(os.Environ(), "CRAWLAB_TASK_ID="+task.Id) - cmd.Env = append(cmd.Env, "CRAWLAB_COLLECTION="+col) - cmd.Env = append(cmd.Env, "CRAWLAB_MONGO_HOST="+viper.GetString("mongo.host")) - cmd.Env = append(cmd.Env, "CRAWLAB_MONGO_PORT="+viper.GetString("mongo.port")) - if viper.GetString("mongo.db") != "" { - cmd.Env = append(cmd.Env, "CRAWLAB_MONGO_DB="+viper.GetString("mongo.db")) - } - if viper.GetString("mongo.username") != "" { - cmd.Env = append(cmd.Env, "CRAWLAB_MONGO_USERNAME="+viper.GetString("mongo.username")) - } - if viper.GetString("mongo.password") != "" { - cmd.Env = append(cmd.Env, "CRAWLAB_MONGO_PASSWORD="+viper.GetString("mongo.password")) - } - if viper.GetString("mongo.authSource") != "" { - cmd.Env = append(cmd.Env, "CRAWLAB_MONGO_AUTHSOURCE="+viper.GetString("mongo.authSource")) - } - cmd.Env = append(cmd.Env, "PYTHONUNBUFFERED=0") - cmd.Env = append(cmd.Env, "PYTHONIOENCODING=utf-8") - cmd.Env = append(cmd.Env, "TZ=Asia/Shanghai") - cmd.Env = append(cmd.Env, "CRAWLAB_DEDUP_FIELD="+spider.DedupField) - cmd.Env = append(cmd.Env, "CRAWLAB_DEDUP_METHOD="+spider.DedupMethod) - if spider.IsDedup { - cmd.Env = append(cmd.Env, "CRAWLAB_IS_DEDUP=1") - } else { - cmd.Env = append(cmd.Env, "CRAWLAB_IS_DEDUP=0") - } - - //任务环境变量 - for _, env := range envs { - cmd.Env = append(cmd.Env, env.Name+"="+env.Value) - } - - // 全局环境变量 - variables := model.GetVariableList() - for _, variable := range variables { - cmd.Env = append(cmd.Env, variable.Key+"="+variable.Value) - } - return cmd -} - -func SetLogConfig(wg *sync.WaitGroup, cmd *exec.Cmd, t model.Task, u model.User) error { - - esChan := make(chan string, 1) - esClientStr := viper.GetString("setting.esClient") - spiderLogIndex := viper.GetString("setting.spiderLogIndex") - // get stdout reader - stdout, err := cmd.StdoutPipe() - if err != nil { - log.Errorf("get stdout error: %s", err.Error()) - debug.PrintStack() - return err - } - readerStdout := bufio.NewReader(stdout) - - // get stderr reader - stderr, err := cmd.StderrPipe() - if err != nil { - log.Errorf("get stdout error: %s", err.Error()) - debug.PrintStack() - return err - } - readerStderr := bufio.NewReader(stderr) - - var seq int64 - var logs []model.LogItem - isStdoutFinished := false - isStderrFinished := false - - // periodically (5 sec) insert log items - wg.Add(3) - go func() { - defer wg.Done() - for { - _ = model.AddLogItems(logs) - logs = []model.LogItem{} - if isStdoutFinished && isStderrFinished { - break - } - time.Sleep(5 * time.Second) - } - }() - - // expire duration (in seconds) - expireDuration := u.Setting.LogExpireDuration - if expireDuration == 0 { - // by default 1 day - expireDuration = 3600 * 24 - } - - // read stdout - go func() { - defer wg.Done() - for { - line, err := readerStdout.ReadString('\n') - if err != nil { - isStdoutFinished = true - break - } - line = strings.Replace(line, "\n", "", -1) - seq++ - l := model.LogItem{ - Id: bson.NewObjectId(), - Seq: seq, - Message: line, - TaskId: t.Id, - Ts: time.Now(), - ExpireTs: time.Now().Add(time.Duration(expireDuration) * time.Second), - } - - if esClientStr != "" { - esChan <- l.Message - go database.WriteMsgToES(time.Now(), esChan, spiderLogIndex) - } - - logs = append(logs, l) - } - }() - - // read stderr - go func() { - defer wg.Done() - for { - line, err := readerStderr.ReadString('\n') - if err != nil { - isStderrFinished = true - break - } - line = strings.Replace(line, "\n", "", -1) - seq++ - l := model.LogItem{ - Id: bson.NewObjectId(), - Seq: seq, - Message: line, - TaskId: t.Id, - Ts: time.Now(), - ExpireTs: time.Now().Add(time.Duration(expireDuration) * time.Second), - } - - if esClientStr != "" { - esChan <- l.Message - go database.WriteMsgToES(time.Now(), esChan, spiderLogIndex) - } - logs = append(logs, l) - } - }() - - wg.Wait() - return nil -} - -func FinishOrCancelTask(ch chan string, cmd *exec.Cmd, s model.Spider, t model.Task) { - // 传入信号,此处阻塞 - signal := <-ch - log.Infof("process received signal: %s", signal) - - if signal == constants.TaskCancel && cmd.Process != nil { - // 终止进程 - if err := sys_exec.KillProcess(cmd); err != nil { - log.Errorf("process kill error: %s", err.Error()) - debug.PrintStack() - - t.Error = "kill process error: " + err.Error() - t.Status = constants.StatusError - } else { - t.Error = "user kill the process ..." - t.Status = constants.StatusCancelled - } - } else { - // 保存任务 - t.Status = constants.StatusFinished - } - - t.FinishTs = time.Now() - _ = t.Save() - - go FinishUpTask(s, t) -} - -func StartTaskProcess(cmd *exec.Cmd, t model.Task) error { - if err := cmd.Start(); err != nil { - log.Errorf("start spider error:{}", err.Error()) - debug.PrintStack() - - t.Error = "start task error: " + err.Error() - t.Status = constants.StatusError - t.FinishTs = time.Now() - _ = t.Save() - return err - } - return nil -} - -func WaitTaskProcess(cmd *exec.Cmd, t model.Task, s model.Spider) error { - if err := cmd.Wait(); err != nil { - log.Errorf("wait process finish error: %s", err.Error()) - debug.PrintStack() - - if exitError, ok := err.(*exec.ExitError); ok { - exitCode := exitError.ExitCode() - log.Errorf("exit error, exit code: %d", exitCode) - - // 非kill 的错误类型 - if exitCode != -1 { - // 非手动kill保存为错误状态 - t.Error = err.Error() - t.FinishTs = time.Now() - t.Status = constants.StatusError - _ = t.Save() - - FinishUpTask(s, t) - } - } - - return err - } - - return nil -} - -// 执行shell命令 -func ExecuteShellCmd(cmdStr string, cwd string, t model.Task, s model.Spider, u model.User) (err error) { - log.Infof("cwd: %s", cwd) - log.Infof("cmd: %s", cmdStr) - - wg := &sync.WaitGroup{} - - // 生成执行命令 - cmd := sys_exec.BuildCmd(cmdStr) - - // 工作目录 - cmd.Dir = cwd - - // 日志配置 - go SetLogConfig(wg, cmd, t, u) - - // 环境变量配置 - envs := s.Envs - if s.Type == constants.Configurable { - // 数据库配置 - envs = append(envs, model.Env{Name: "CRAWLAB_MONGO_HOST", Value: viper.GetString("mongo.host")}) - envs = append(envs, model.Env{Name: "CRAWLAB_MONGO_PORT", Value: viper.GetString("mongo.port")}) - envs = append(envs, model.Env{Name: "CRAWLAB_MONGO_DB", Value: viper.GetString("mongo.db")}) - envs = append(envs, model.Env{Name: "CRAWLAB_MONGO_USERNAME", Value: viper.GetString("mongo.username")}) - envs = append(envs, model.Env{Name: "CRAWLAB_MONGO_PASSWORD", Value: viper.GetString("mongo.password")}) - envs = append(envs, model.Env{Name: "CRAWLAB_MONGO_AUTHSOURCE", Value: viper.GetString("mongo.authSource")}) - - // 设置配置 - for envName, envValue := range s.Config.Settings { - envs = append(envs, model.Env{Name: "CRAWLAB_SETTING_" + envName, Value: envValue}) - } - } - cmd = SetEnv(cmd, envs, t, s) - - // 起一个goroutine来监控进程 - ch := utils.TaskExecChanMap.ChanBlocked(t.Id) - go FinishOrCancelTask(ch, cmd, s, t) - - // kill的时候,可以kill所有的子进程 - sys_exec.Setpgid(cmd) - - // 启动进程 - if err := StartTaskProcess(cmd, t); err != nil { - return err - } - - // 同步等待进程完成 - if err := WaitTaskProcess(cmd, t, s); err != nil { - return err - } - - // 如果返回值不为0,返回错误 - returnCode := cmd.ProcessState.ExitCode() - if returnCode != 0 { - log.Errorf(fmt.Sprintf("task returned code not zero: %d", returnCode)) - debug.PrintStack() - return errors.New(fmt.Sprintf("task returned code not zero: %d", returnCode)) - } - - ch <- constants.TaskFinish - return nil -} - -// 生成执行任务方法 -func GetExecuteTaskFunc(id int) func() { - return func() { - ExecuteTask(id) - } -} - -func GetWorkerPrefix(id int) string { - return "[Worker " + strconv.Itoa(id) + "] " -} - -// 统计任务结果数 -func SaveTaskResultCount(id string) func() { - return func() { - if err := model.UpdateTaskResultCount(id); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return - } - } -} - -// Scan Error Logs -func ScanErrorLogs(t model.Task) func() { - return func() { - u, err := model.GetUser(t.UserId) - if err != nil { - return - } - if err := model.UpdateTaskErrorLogs(t.Id, u.Setting.ErrorRegexPattern); err != nil { - return - } - if err := model.UpdateErrorLogCount(t.Id); err != nil { - return - } - } -} - -// 执行任务 -func ExecuteTask(id int) { - if flag, ok := LockList.Load(id); ok { - if flag.(bool) { - log.Debugf(GetWorkerPrefix(id) + "running tasks...") - return - } - } - - // 上锁 - LockList.Store(id, true) - - // 解锁(延迟执行) - defer func() { - LockList.Delete(id) - LockList.Store(id, false) - }() - - // 开始计时 - tic := time.Now() - - // 获取当前节点 - //node, err := model.GetCurrentNode() - //if err != nil { - // log.Errorf("execute task get current node error: %s", err.Error()) - // debug.PrintStack() - // return - //} - node := local_node.CurrentNode() - - // 节点队列 - queueCur := "tasks:node:" + node.Id.Hex() - - // 节点队列任务 - var msg string - var err error - if msg, err = database.RedisClient.LPop(queueCur); err != nil { - // 节点队列没有任务,获取公共队列任务 - queuePub := "tasks:public" - if msg, err = database.RedisClient.LPop(queuePub); err != nil { - } - } - - // 如果没有获取到任务,返回 - if msg == "" { - return - } - - // 反序列化 - tMsg := TaskMessage{} - if err := json.Unmarshal([]byte(msg), &tMsg); err != nil { - log.Errorf("json string to struct error: %s", err.Error()) - return - } - - // 获取任务 - t, err := model.GetTask(tMsg.Id) - if err != nil { - log.Errorf("execute task, get task error: %s", err.Error()) - return - } - - // 获取爬虫 - var spider model.Spider - if t.Type == constants.TaskTypeSpider { - spider, err = t.GetSpider() - if err != nil { - log.Errorf("execute task, get spider error: %s", err.Error()) - return - } - } - - // 工作目录 - cwd := filepath.Join( - viper.GetString("spider.path"), - spider.Name, - ) - - // 执行命令 - var cmd string - if t.Type == constants.TaskTypeSpider { - // 爬虫任务 - if spider.Type == constants.Configurable { - // 可配置爬虫命令 - cmd = "scrapy crawl config_spider" - } else { - // 自定义爬虫命令 - cmd = spider.Cmd - } - t.Cmd = cmd - } else if t.Type == constants.TaskTypeSystem { - // 系统任务 - cmd = t.Cmd - } - - // 加入参数 - if t.Param != "" { - cmd += " " + t.Param - } - - // 获得触发任务用户 - user, err := model.GetUser(t.UserId) - if err != nil { - log.Errorf(GetWorkerPrefix(id) + err.Error()) - return - } - - // 任务赋值 - t.NodeId = node.Id // 任务节点信息 - t.StartTs = time.Now() // 任务开始时间 - t.Status = constants.StatusRunning // 任务状态 - t.WaitDuration = t.StartTs.Sub(t.CreateTs).Seconds() // 等待时长 - - // 储存任务 - _ = t.Save() - - // 发送 Web Hook 请求 (任务开始) - go SendWebHookRequest(user, t, spider) - - // 爬虫任务专属逻辑 - if t.Type == constants.TaskTypeSpider { - // 文件检查 - if err := SpiderFileCheck(t, spider); err != nil { - log.Errorf("spider file check error: %s", err.Error()) - return - } - - // 开始执行任务 - log.Infof(GetWorkerPrefix(id) + "start task (id:" + t.Id + ")") - - // 创建结果集索引 - go func() { - col := utils.GetSpiderCol(spider.Col, spider.Name) - CreateResultsIndexes(col) - }() - - // 起一个cron执行器来统计任务结果数 - cronExec := cron.New(cron.WithSeconds()) - _, err = cronExec.AddFunc("*/5 * * * * *", SaveTaskResultCount(t.Id)) - if err != nil { - log.Errorf(GetWorkerPrefix(id) + err.Error()) - debug.PrintStack() - return - } - cronExec.Start() - defer cronExec.Stop() - - // 起一个cron来更新错误日志 - cronExecErrLog := cron.New(cron.WithSeconds()) - _, err = cronExecErrLog.AddFunc("*/30 * * * * *", ScanErrorLogs(t)) - if err != nil { - log.Errorf(GetWorkerPrefix(id) + err.Error()) - debug.PrintStack() - return - } - cronExecErrLog.Start() - defer cronExecErrLog.Stop() - } - - // 执行Shell命令 - if err := ExecuteShellCmd(cmd, cwd, t, spider, user); err != nil { - log.Errorf(GetWorkerPrefix(id) + err.Error()) - - // 如果发生错误,则发送通知 - t, _ = model.GetTask(t.Id) - if user.Setting.NotificationTrigger == constants.NotificationTriggerOnTaskEnd || user.Setting.NotificationTrigger == constants.NotificationTriggerOnTaskError { - SendNotifications(user, t, spider) - } - - // 发送 Web Hook 请求 (任务开始) - go SendWebHookRequest(user, t, spider) - - return - } - - // 完成进程 - t, err = model.GetTask(t.Id) - if err != nil { - log.Errorf(GetWorkerPrefix(id) + err.Error()) - return - } - - // 统计数据 - t.Status = constants.StatusFinished // 任务状态: 已完成 - t.FinishTs = time.Now() // 结束时间 - t.RuntimeDuration = t.FinishTs.Sub(t.StartTs).Seconds() // 运行时长 - t.TotalDuration = t.FinishTs.Sub(t.CreateTs).Seconds() // 总时长 - - // 发送 Web Hook 请求 (任务结束) - go SendWebHookRequest(user, t, spider) - - // 如果是任务结束时发送通知,则发送通知 - if user.Setting.NotificationTrigger == constants.NotificationTriggerOnTaskEnd { - SendNotifications(user, t, spider) - } - - // 保存任务 - if err := t.Save(); err != nil { - log.Errorf(GetWorkerPrefix(id) + err.Error()) - return - } - - // 完成任务收尾工作 - go FinishUpTask(spider, t) - - // 结束计时 - toc := time.Now() - - // 统计时长 - duration := toc.Sub(tic).Seconds() - durationStr := strconv.FormatFloat(duration, 'f', 6, 64) - log.Infof(GetWorkerPrefix(id) + "task (id:" + t.Id + ")" + " finished. elapsed:" + durationStr + " sec") -} - -func FinishUpTask(s model.Spider, t model.Task) { - // 更新任务结果数 - if t.Type == constants.TaskTypeSpider { - go func() { - if err := model.UpdateTaskResultCount(t.Id); err != nil { - return - } - }() - } - - // 更新任务错误日志 - go func() { - ScanErrorLogs(t)() - }() -} - -func SpiderFileCheck(t model.Task, spider model.Spider) error { - // 判断爬虫文件是否存在 - gfFile := model.GetGridFs(spider.FileId) - if gfFile == nil { - t.Error = "cannot find spider files, please re-upload" - t.Status = constants.StatusError - t.FinishTs = time.Now() // 结束时间 - t.RuntimeDuration = t.FinishTs.Sub(t.StartTs).Seconds() // 运行时长 - t.TotalDuration = t.FinishTs.Sub(t.CreateTs).Seconds() // 总时长 - _ = t.Save() - return errors.New(t.Error) - } - - // 判断md5值是否一致 - path := filepath.Join(viper.GetString("spider.path"), spider.Name) - md5File := filepath.Join(path, spider_handler.Md5File) - md5 := utils.GetSpiderMd5Str(md5File) - if gfFile.Md5 != md5 { - spiderSync := spider_handler.SpiderSync{Spider: spider} - spiderSync.RemoveDownCreate(gfFile.Md5) - } - return nil -} - -func GetTaskLog(id string, keyword string, page int, pageSize int) (logItems []model.LogItem, logTotal int, err error) { - task, err := model.GetTask(id) - if err != nil { - return - } - - logItems, logTotal, err = task.GetLogItems(keyword, page, pageSize) - if err != nil { - return logItems, logTotal, err - } - - return logItems, logTotal, nil -} - -func GetTaskErrorLog(id string, n int) (errLogItems []model.ErrorLogItem, err error) { - if n == 0 { - n = 1000 - } - - task, err := model.GetTask(id) - if err != nil { - return - } - errLogItems, err = task.GetErrorLogItems(n) - if err != nil { - return - } - return errLogItems, nil -} - -func CancelTask(id string) (err error) { - // 获取任务 - task, err := model.GetTask(id) - if err != nil { - log.Errorf("task not found, task id : %s, error: %s", id, err.Error()) - debug.PrintStack() - return err - } - - // 如果任务状态不为pending或running,返回错误 - if task.Status != constants.StatusPending && task.Status != constants.StatusRunning { - return errors.New("task is not cancellable") - } - - // 获取当前节点(默认当前节点为主节点) - //node, err := model.GetCurrentNode() - //if err != nil { - // log.Errorf("get current node error: %s", err.Error()) - // debug.PrintStack() - // return err - //} - node := local_node.CurrentNode() - - log.Infof("current node id is: %s", node.Id.Hex()) - log.Infof("task node id is: %s", task.NodeId.Hex()) - - if node.Id == task.NodeId { - // 任务节点为主节点 - if err := rpc.CancelTaskLocal(task.Id, task.NodeId.Hex()); err != nil { - return err - } - } else { - // 任务节点为工作节点 - if err := rpc.CancelTaskRemote(task.Id, task.NodeId.Hex()); err != nil { - return err - } - } - - return nil -} - -func RestartTask(id string, uid bson.ObjectId) (err error) { - // 获取任务 - oldTask, err := model.GetTask(id) - if err != nil { - log.Errorf("task not found, task id : %s, error: %s", id, err.Error()) - debug.PrintStack() - return err - } - - newTask := model.Task{ - SpiderId: oldTask.SpiderId, - NodeId: oldTask.NodeId, - Cmd: oldTask.Cmd, - Param: oldTask.Param, - UserId: uid, - RunType: oldTask.RunType, - ScheduleId: bson.ObjectIdHex(constants.ObjectIdNull), - Type: oldTask.Type, - } - - // 加入任务队列 - _, err = AddTask(newTask) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return err - } - - return nil -} - -func AddTask(t model.Task) (string, error) { - // 生成任务ID - id := uuid.NewV4() - t.Id = id.String() - - // 设置任务状态 - t.Status = constants.StatusPending - - // 如果没有传入node_id,则置为null - if t.NodeId.Hex() == "" { - t.NodeId = bson.ObjectIdHex(constants.ObjectIdNull) - } - - // 将任务存入数据库 - if err := model.AddTask(t); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return t.Id, err - } - - // 加入任务队列 - if err := AssignTask(t); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return t.Id, err - } - - return t.Id, nil -} - -func GetTaskEmailMarkdownContent(t model.Task, s model.Spider) string { - n, _ := model.GetNode(t.NodeId) - errMsg := "" - statusMsg := fmt.Sprintf(`%s`, t.Status) - if t.Status == constants.StatusError { - errMsg = " with errors" - statusMsg = fmt.Sprintf(`%s`, t.Status) - } - return fmt.Sprintf(` -Your task has finished%s. Please find the task info below. - - | ---: | :-- -**Task ID:** | %s -**Task Status:** | %s -**Task Param:** | %s -**Spider ID:** | %s -**Spider Name:** | %s -**Node:** | %s -**Create Time:** | %s -**Start Time:** | %s -**Finish Time:** | %s -**Wait Duration:** | %.0f sec -**Runtime Duration:** | %.0f sec -**Total Duration:** | %.0f sec -**Number of Results:** | %d -**Error:** | %s - -Please login to Crawlab to view the details. -`, - errMsg, - t.Id, - statusMsg, - t.Param, - s.Id.Hex(), - s.Name, - n.Name, - utils.GetLocalTimeString(t.CreateTs), - utils.GetLocalTimeString(t.StartTs), - utils.GetLocalTimeString(t.FinishTs), - t.WaitDuration, - t.RuntimeDuration, - t.TotalDuration, - t.ResultCount, - t.Error, - ) -} - -func GetTaskMarkdownContent(t model.Task, s model.Spider) string { - n, _ := model.GetNode(t.NodeId) - errMsg := "" - errLog := "-" - statusMsg := fmt.Sprintf(`%s`, t.Status) - if t.Status == constants.StatusError { - errMsg = `(有错误)` - errLog = fmt.Sprintf(`%s`, t.Error) - statusMsg = fmt.Sprintf(`%s`, t.Status) - } - return fmt.Sprintf(` -您的任务已完成%s,请查看任务信息如下。 - -> **任务ID:** %s -> **任务状态:** %s -> **任务参数:** %s -> **爬虫ID:** %s -> **爬虫名称:** %s -> **节点:** %s -> **创建时间:** %s -> **开始时间:** %s -> **完成时间:** %s -> **等待时间:** %.0f秒 -> **运行时间:** %.0f秒 -> **总时间:** %.0f秒 -> **结果数:** %d -> **错误:** %s - -请登录Crawlab查看详情。 -`, - errMsg, - t.Id, - statusMsg, - t.Param, - s.Id.Hex(), - s.Name, - n.Name, - utils.GetLocalTimeString(t.CreateTs), - utils.GetLocalTimeString(t.StartTs), - utils.GetLocalTimeString(t.FinishTs), - t.WaitDuration, - t.RuntimeDuration, - t.TotalDuration, - t.ResultCount, - errLog, - ) -} - -func CreateResultsIndexes(col string) { - s, c := database.GetCol(col) - defer s.Close() - - _ = c.EnsureIndex(mgo.Index{ - Key: []string{"task_id"}, - }) -} - -func SendTaskEmail(u model.User, t model.Task, s model.Spider) { - statusMsg := "has finished" - if t.Status == constants.StatusError { - statusMsg = "has an error" - } - title := fmt.Sprintf("[Crawlab] Task for \"%s\" %s", s.Name, statusMsg) - if err := notification.SendMail( - u.Email, - u.Username, - title, - GetTaskEmailMarkdownContent(t, s), - ); err != nil { - log.Errorf("mail error: " + err.Error()) - debug.PrintStack() - } -} - -func SendTaskDingTalk(u model.User, t model.Task, s model.Spider) { - statusMsg := "已完成" - if t.Status == constants.StatusError { - statusMsg = "发生错误" - } - title := fmt.Sprintf("[Crawlab] \"%s\" 任务%s", s.Name, statusMsg) - content := GetTaskMarkdownContent(t, s) - if err := notification.SendMobileNotification(u.Setting.DingTalkRobotWebhook, title, content); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - } -} - -func SendTaskWechat(u model.User, t model.Task, s model.Spider) { - content := GetTaskMarkdownContent(t, s) - if err := notification.SendMobileNotification(u.Setting.WechatRobotWebhook, "", content); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - } -} - -func SendNotifications(u model.User, t model.Task, s model.Spider) { - if u.Email != "" && utils.StringArrayContains(u.Setting.EnabledNotifications, constants.NotificationTypeMail) { - go func() { - SendTaskEmail(u, t, s) - }() - } - - if u.Setting.DingTalkRobotWebhook != "" && utils.StringArrayContains(u.Setting.EnabledNotifications, constants.NotificationTypeDingTalk) { - go func() { - SendTaskDingTalk(u, t, s) - }() - } - - if u.Setting.WechatRobotWebhook != "" && utils.StringArrayContains(u.Setting.EnabledNotifications, constants.NotificationTypeWechat) { - go func() { - SendTaskWechat(u, t, s) - }() - } -} - -func SendWebHookRequest(u model.User, t model.Task, s model.Spider) { - type RequestBody struct { - Status string `json:"status"` - Task model.Task `json:"task"` - Spider model.Spider `json:"spider"` - UserName string `json:"user_name"` - } - - if s.IsWebHook && s.WebHookUrl != "" { - // request header - header := req.Header{ - "Content-Type": "application/json; charset=utf-8", - } - - // request body - reqBody := RequestBody{ - Status: t.Status, - UserName: u.Username, - Task: t, - Spider: s, - } - - // make POST http request - res, err := req.Post(s.WebHookUrl, header, req.BodyJSON(reqBody)) - if err != nil { - log.Errorf("sent web hook request with error: " + err.Error()) - debug.PrintStack() - return - } - if res.Response().StatusCode != http.StatusOK { - log.Errorf(fmt.Sprintf("sent web hook request with error http code: %d, task_id: %s, status: %s", res.Response().StatusCode, t.Id, t.Status)) - debug.PrintStack() - return - } - log.Infof(fmt.Sprintf("sent web hook request, task_id: %s, status: %s)", t.Id, t.Status)) - } -} - -func InitTaskExecutor() error { - // 构造任务执行器 - c := cron.New(cron.WithSeconds()) - Exec = &Executor{ - Cron: c, - } - - // 如果不允许主节点运行任务,则跳过 - if model.IsMaster() && viper.GetString("setting.runOnMaster") == "N" { - return nil - } - - // 运行定时任务 - if err := Exec.Start(); err != nil { - return err - } - return nil -} diff --git a/backend/services/user.go b/backend/services/user.go deleted file mode 100644 index fbad2c71..00000000 --- a/backend/services/user.go +++ /dev/null @@ -1,133 +0,0 @@ -package services - -import ( - "crawlab/constants" - "crawlab/model" - "crawlab/utils" - "errors" - "github.com/dgrijalva/jwt-go" - "github.com/gin-gonic/gin" - "github.com/globalsign/mgo/bson" - "github.com/spf13/viper" - "strings" - "time" -) - -func InitUserService() error { - _ = CreateNewUser("admin", "admin", constants.RoleAdmin, "", bson.ObjectIdHex(constants.ObjectIdNull)) - return nil -} - -func MakeToken(user *model.User) (tokenStr string, err error) { - token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ - "id": user.Id, - "username": user.Username, - "nbf": time.Now().Unix(), - }) - - return token.SignedString([]byte(viper.GetString("server.secret"))) - -} - -//func GetToken(username string) (tokenStr string, err error) { -// user, err := model.GetUserByUsername(username) -// if err != nil { -// log.Errorf(err.Error()) -// debug.PrintStack() -// return -// } -// -// token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ -// "id": user.Id, -// "username": user.Username, -// "nbf": time.Now().Unix(), -// }) -// -// tokenStr, err = token.SignedString([]byte(viper.GetString("server.secret"))) -// if err != nil { -// return -// } -// return -//} - -func SecretFunc() jwt.Keyfunc { - return func(token *jwt.Token) (interface{}, error) { - return []byte(viper.GetString("server.secret")), nil - } -} - -func CheckToken(tokenStr string) (user model.User, err error) { - token, err := jwt.Parse(tokenStr, SecretFunc()) - if err != nil { - return - } - - claim, ok := token.Claims.(jwt.MapClaims) - if !ok { - err = errors.New("cannot convert claim to mapclaim") - return - } - - //验证token,如果token被修改过则为false - if !token.Valid { - err = errors.New("token is invalid") - return - } - - id := bson.ObjectIdHex(claim["id"].(string)) - username := claim["username"].(string) - user, err = model.GetUser(id) - if err != nil { - err = errors.New("cannot get user") - return - } - - if username != user.Username { - err = errors.New("username does not match") - return - } - - return -} - -func CreateNewUser(username string, password string, role string, email string, uid bson.ObjectId) error { - user := model.User{ - Username: strings.ToLower(username), - Password: utils.EncryptPassword(password), - Role: role, - Email: email, - UserId: uid, - Setting: model.UserSetting{ - NotificationTrigger: constants.NotificationTriggerNever, - EnabledNotifications: []string{ - constants.NotificationTypeMail, - constants.NotificationTypeDingTalk, - constants.NotificationTypeWechat, - }, - }, - } - if err := user.Add(); err != nil { - return err - } - return nil -} - -func GetCurrentUser(c *gin.Context) *model.User { - data, _ := c.Get(constants.ContextUser) - if data == nil { - return &model.User{} - } - return data.(*model.User) -} - -func GetCurrentUserId(c *gin.Context) bson.ObjectId { - return GetCurrentUser(c).Id -} - -func GetAdminUser() (user *model.User, err error) { - u, err := model.GetUserByUsername("admin") - if err != nil { - return user, err - } - return &u, nil -} diff --git a/backend/services/version.go b/backend/services/version.go deleted file mode 100644 index 34df7b22..00000000 --- a/backend/services/version.go +++ /dev/null @@ -1,29 +0,0 @@ -package services - -import ( - "crawlab/entity" - "github.com/apex/log" - "github.com/imroc/req" - "runtime/debug" - "sort" -) - -func GetLatestRelease() (release entity.Release, err error) { - res, err := req.Get("https://api.github.com/repos/crawlab-team/crawlab/releases") - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return release, err - } - - var releaseDataList entity.ReleaseSlices - if err := res.ToJSON(&releaseDataList); err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return release, err - } - - sort.Sort(releaseDataList) - - return releaseDataList[len(releaseDataList)-1], nil -} diff --git a/backend/template/scrapy/config_spider/__init__.py b/backend/template/scrapy/config_spider/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/template/scrapy/config_spider/items.py b/backend/template/scrapy/config_spider/items.py deleted file mode 100644 index 16681a52..00000000 --- a/backend/template/scrapy/config_spider/items.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your scraped items -# -# See documentation in: -# https://docs.scrapy.org/en/latest/topics/items.html - -import scrapy - - -class Item(scrapy.Item): -###ITEMS### diff --git a/backend/template/scrapy/config_spider/middlewares.py b/backend/template/scrapy/config_spider/middlewares.py deleted file mode 100644 index e864bd0b..00000000 --- a/backend/template/scrapy/config_spider/middlewares.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your spider middleware -# -# See documentation in: -# https://docs.scrapy.org/en/latest/topics/spider-middleware.html - -from scrapy import signals - - -class ConfigSpiderSpiderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the spider middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_spider_input(self, response, spider): - # Called for each response that goes through the spider - # middleware and into the spider. - - # Should return None or raise an exception. - return None - - def process_spider_output(self, response, result, spider): - # Called with the results returned from the Spider, after - # it has processed the response. - - # Must return an iterable of Request, dict or Item objects. - for i in result: - yield i - - def process_spider_exception(self, response, exception, spider): - # Called when a spider or process_spider_input() method - # (from other spider middleware) raises an exception. - - # Should return either None or an iterable of Request, dict - # or Item objects. - pass - - def process_start_requests(self, start_requests, spider): - # Called with the start requests of the spider, and works - # similarly to the process_spider_output() method, except - # that it doesn’t have a response associated. - - # Must return only requests (not items). - for r in start_requests: - yield r - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) - - -class ConfigSpiderDownloaderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the downloader middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_request(self, request, spider): - # Called for each request that goes through the downloader - # middleware. - - # Must either: - # - return None: continue processing this request - # - or return a Response object - # - or return a Request object - # - or raise IgnoreRequest: process_exception() methods of - # installed downloader middleware will be called - return None - - def process_response(self, request, response, spider): - # Called with the response returned from the downloader. - - # Must either; - # - return a Response object - # - return a Request object - # - or raise IgnoreRequest - return response - - def process_exception(self, request, exception, spider): - # Called when a download handler or a process_request() - # (from other downloader middleware) raises an exception. - - # Must either: - # - return None: continue processing this exception - # - return a Response object: stops process_exception() chain - # - return a Request object: stops process_exception() chain - pass - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) diff --git a/backend/template/scrapy/config_spider/pipelines.py b/backend/template/scrapy/config_spider/pipelines.py deleted file mode 100644 index 69af4c85..00000000 --- a/backend/template/scrapy/config_spider/pipelines.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define your item pipelines here -# -# Don't forget to add your pipeline to the ITEM_PIPELINES setting -# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html - -import os -from pymongo import MongoClient - -mongo = MongoClient( - host=os.environ.get('CRAWLAB_MONGO_HOST') or 'localhost', - port=int(os.environ.get('CRAWLAB_MONGO_PORT') or 27017), - username=os.environ.get('CRAWLAB_MONGO_USERNAME'), - password=os.environ.get('CRAWLAB_MONGO_PASSWORD'), - authSource=os.environ.get('CRAWLAB_MONGO_AUTHSOURCE') or 'admin' -) -db = mongo[os.environ.get('CRAWLAB_MONGO_DB') or 'test'] -col = db[os.environ.get('CRAWLAB_COLLECTION') or 'test'] -task_id = os.environ.get('CRAWLAB_TASK_ID') - -class ConfigSpiderPipeline(object): - def process_item(self, item, spider): - item['task_id'] = task_id - if col is not None: - col.save(item) - return item diff --git a/backend/template/scrapy/config_spider/settings.py b/backend/template/scrapy/config_spider/settings.py deleted file mode 100644 index 4b0965f2..00000000 --- a/backend/template/scrapy/config_spider/settings.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8 -*- -import os -import re -import json - -# Scrapy settings for config_spider project -# -# For simplicity, this file contains only settings considered important or -# commonly used. You can find more settings consulting the documentation: -# -# https://docs.scrapy.org/en/latest/topics/settings.html -# https://docs.scrapy.org/en/latest/topics/downloader-middleware.html -# https://docs.scrapy.org/en/latest/topics/spider-middleware.html - -BOT_NAME = 'Crawlab Configurable Spider' - -SPIDER_MODULES = ['config_spider.spiders'] -NEWSPIDER_MODULE = 'config_spider.spiders' - - -# Crawl responsibly by identifying yourself (and your website) on the user-agent -USER_AGENT = 'Crawlab Spider' - -# Obey robots.txt rules -ROBOTSTXT_OBEY = True - -# Configure maximum concurrent requests performed by Scrapy (default: 16) -#CONCURRENT_REQUESTS = 32 - -# Configure a delay for requests for the same website (default: 0) -# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay -# See also autothrottle settings and docs -#DOWNLOAD_DELAY = 3 -# The download delay setting will honor only one of: -#CONCURRENT_REQUESTS_PER_DOMAIN = 16 -#CONCURRENT_REQUESTS_PER_IP = 16 - -# Disable cookies (enabled by default) -#COOKIES_ENABLED = False - -# Disable Telnet Console (enabled by default) -#TELNETCONSOLE_ENABLED = False - -# Override the default request headers: -#DEFAULT_REQUEST_HEADERS = { -# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', -# 'Accept-Language': 'en', -#} - -# Enable or disable spider middlewares -# See https://docs.scrapy.org/en/latest/topics/spider-middleware.html -#SPIDER_MIDDLEWARES = { -# 'config_spider.middlewares.ConfigSpiderSpiderMiddleware': 543, -#} - -# Enable or disable downloader middlewares -# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html -#DOWNLOADER_MIDDLEWARES = { -# 'config_spider.middlewares.ConfigSpiderDownloaderMiddleware': 543, -#} - -# Enable or disable extensions -# See https://docs.scrapy.org/en/latest/topics/extensions.html -#EXTENSIONS = { -# 'scrapy.extensions.telnet.TelnetConsole': None, -#} - -# Configure item pipelines -# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html -ITEM_PIPELINES = { - 'config_spider.pipelines.ConfigSpiderPipeline': 300, -} - -# Enable and configure the AutoThrottle extension (disabled by default) -# See https://docs.scrapy.org/en/latest/topics/autothrottle.html -#AUTOTHROTTLE_ENABLED = True -# The initial download delay -#AUTOTHROTTLE_START_DELAY = 5 -# The maximum download delay to be set in case of high latencies -#AUTOTHROTTLE_MAX_DELAY = 60 -# The average number of requests Scrapy should be sending in parallel to -# each remote server -#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 -# Enable showing throttling stats for every response received: -#AUTOTHROTTLE_DEBUG = False - -# Enable and configure HTTP caching (disabled by default) -# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings -#HTTPCACHE_ENABLED = True -#HTTPCACHE_EXPIRATION_SECS = 0 -#HTTPCACHE_DIR = 'httpcache' -#HTTPCACHE_IGNORE_HTTP_CODES = [] -#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' - -for setting_env_name in [x for x in os.environ.keys() if x.startswith('CRAWLAB_SETTING_')]: - setting_name = setting_env_name.replace('CRAWLAB_SETTING_', '') - setting_value = os.environ.get(setting_env_name) - if setting_value.lower() == 'true': - setting_value = True - elif setting_value.lower() == 'false': - setting_value = False - elif re.search(r'^\d+$', setting_value) is not None: - setting_value = int(setting_value) - elif re.search(r'^\{.*\}$', setting_value.strip()) is not None: - setting_value = json.loads(setting_value) - elif re.search(r'^\[.*\]$', setting_value.strip()) is not None: - setting_value = json.loads(setting_value) - else: - pass - locals()[setting_name] = setting_value - diff --git a/backend/template/scrapy/config_spider/spiders/__init__.py b/backend/template/scrapy/config_spider/spiders/__init__.py deleted file mode 100644 index ebd689ac..00000000 --- a/backend/template/scrapy/config_spider/spiders/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# This package will contain the spiders of your Scrapy project -# -# Please refer to the documentation for information on how to create and manage -# your spiders. diff --git a/backend/template/scrapy/config_spider/spiders/spider.py b/backend/template/scrapy/config_spider/spiders/spider.py deleted file mode 100644 index 09dfdf5e..00000000 --- a/backend/template/scrapy/config_spider/spiders/spider.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -import scrapy -import re -from config_spider.items import Item -from urllib.parse import urljoin, urlparse - -def get_real_url(response, url): - if re.search(r'^https?', url): - return url - elif re.search(r'^\/\/', url): - u = urlparse(response.url) - return u.scheme + ":" + url - return urljoin(response.url, url) - -class ConfigSpider(scrapy.Spider): - name = 'config_spider' - - def start_requests(self): - yield scrapy.Request(url='###START_URL###', callback=self.###START_STAGE###) - -###PARSERS### diff --git a/backend/template/scrapy/scrapy.cfg b/backend/template/scrapy/scrapy.cfg deleted file mode 100644 index a78d91e3..00000000 --- a/backend/template/scrapy/scrapy.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Automatically created by: scrapy startproject -# -# For more information about the [deploy] section see: -# https://scrapyd.readthedocs.io/en/latest/deploy.html - -[settings] -default = config_spider.settings - -[deploy] -#url = http://localhost:6800/ -project = config_spider diff --git a/backend/template/spiderfile/Spiderfile.163_news b/backend/template/spiderfile/Spiderfile.163_news deleted file mode 100644 index b87b8888..00000000 --- a/backend/template/spiderfile/Spiderfile.163_news +++ /dev/null @@ -1,19 +0,0 @@ -name: "toscrapy_books" -start_url: "http://news.163.com/special/0001386F/rank_news.html" -start_stage: "list" -engine: "scrapy" -stages: -- name: list - is_list: true - list_css: "table tr:not(:first-child)" - fields: - - name: "title" - css: "td:nth-child(1) > a" - - name: "url" - css: "td:nth-child(1) > a" - attr: "href" - - name: "clicks" - css: "td.cBlue" -settings: - ROBOTSTXT_OBEY: false - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36 diff --git a/backend/template/spiderfile/Spiderfile.baidu b/backend/template/spiderfile/Spiderfile.baidu deleted file mode 100644 index 0259c64f..00000000 --- a/backend/template/spiderfile/Spiderfile.baidu +++ /dev/null @@ -1,21 +0,0 @@ -name: toscrapy_books -start_url: http://www.baidu.com/s?wd=crawlab -start_stage: list -engine: scrapy -stages: -- name: list - is_list: true - list_xpath: //*[contains(@class, "c-container")] - page_xpath: //*[@id="page"]//a[@class="n"][last()] - page_attr: href - fields: - - name: title - xpath: .//h3/a - - name: url - xpath: .//h3/a - attr: href - - name: abstract - xpath: .//*[@class="c-abstract"] -settings: - ROBOTSTXT_OBEY: false - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36 diff --git a/backend/template/spiderfile/Spiderfile.toscrapy_books b/backend/template/spiderfile/Spiderfile.toscrapy_books deleted file mode 100644 index d9100e21..00000000 --- a/backend/template/spiderfile/Spiderfile.toscrapy_books +++ /dev/null @@ -1,27 +0,0 @@ -name: "toscrapy_books" -start_url: "http://books.toscrape.com" -start_stage: "list" -engine: "scrapy" -stages: -- name: list - is_list: true - list_css: "section article.product_pod" - page_css: "ul.pager li.next a" - page_attr: "href" - fields: - - name: "title" - css: "h3 > a" - - name: "url" - css: "h3 > a" - attr: "href" - next_stage: "detail" - - name: "price" - css: ".product_price > .price_color" -- name: detail - is_list: false - fields: - - name: "description" - css: "#product_description + p" -settings: - ROBOTSTXT_OBEY: true - AUTOTHROTTLE_ENABLED: true diff --git a/backend/template/spiders/amazon_config/Spiderfile b/backend/template/spiders/amazon_config/Spiderfile deleted file mode 100644 index eea8a538..00000000 --- a/backend/template/spiders/amazon_config/Spiderfile +++ /dev/null @@ -1,51 +0,0 @@ -name: "amazon_config" -display_name: "亚马逊中国(可配置)" -remark: "亚马逊中国搜索手机,列表+分页" -type: "configurable" -col: "results_amazon_config" -engine: scrapy -start_url: https://www.amazon.cn/s?k=%E6%89%8B%E6%9C%BA&__mk_zh_CN=%E4%BA%9A%E9%A9%AC%E9%80%8A%E7%BD%91%E7%AB%99&ref=nb_sb_noss_2 -start_stage: list -stages: -- name: list - is_list: true - list_css: .s-result-item - list_xpath: "" - page_css: .a-last > a - page_xpath: "" - page_attr: href - fields: - - name: title - css: span.a-text-normal - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: url - css: .a-link-normal - xpath: "" - attr: href - next_stage: "" - remark: "" - - name: price - css: "" - xpath: .//*[@class="a-price-whole"] - attr: "" - next_stage: "" - remark: "" - - name: price_fraction - css: "" - xpath: .//*[@class="a-price-fraction"] - attr: "" - next_stage: "" - remark: "" - - name: img - css: .s-image-square-aspect > img - xpath: "" - attr: src - next_stage: "" - remark: "" -settings: - ROBOTSTXT_OBEY: "false" - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, - like Gecko) Chrome/78.0.3904.108 Safari/537.36 diff --git a/backend/template/spiders/autohome_config/Spiderfile b/backend/template/spiders/autohome_config/Spiderfile deleted file mode 100644 index e69880cb..00000000 --- a/backend/template/spiders/autohome_config/Spiderfile +++ /dev/null @@ -1,57 +0,0 @@ -name: "autohome_config" -display_name: "汽车之家(可配置)" -remark: "汽车之家文章,列表+详情+分页" -type: "configurable" -col: "results_autohome_config" -engine: scrapy -start_url: https://www.autohome.com.cn/all/ -start_stage: list -stages: -- name: list - is_list: true - list_css: ul.article > li - list_xpath: "" - page_css: a.page-item-next - page_xpath: "" - page_attr: href - fields: - - name: title - css: li > a > h3 - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: url - css: li > a - xpath: "" - attr: href - next_stage: "" - remark: "" - - name: abstract - css: li > a > p - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: time - css: li > a .fn-left - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: views - css: li > a .fn-right > em:first-child - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: comments - css: li > a .fn-right > em:last-child - xpath: "" - attr: "" - next_stage: "" - remark: "" -settings: - ROBOTSTXT_OBEY: "false" - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, - like Gecko) Chrome/78.0.3904.108 Safari/537.36 diff --git a/backend/template/spiders/baidu_config/Spiderfile b/backend/template/spiders/baidu_config/Spiderfile deleted file mode 100644 index a29d4acb..00000000 --- a/backend/template/spiders/baidu_config/Spiderfile +++ /dev/null @@ -1,39 +0,0 @@ -name: "baidu_config" -display_name: "百度搜索(可配置)" -remark: "百度搜索Crawlab,列表+分页" -type: "configurable" -col: "results_baidu_config" -engine: scrapy -start_url: http://www.baidu.com/s?wd=crawlab -start_stage: list -stages: -- name: list - is_list: true - list_css: ".result.c-container" - list_xpath: "" - page_css: "a.n" - page_xpath: "" - page_attr: href - fields: - - name: title - css: "" - xpath: .//h3/a - attr: "" - next_stage: "" - remark: "" - - name: url - css: "" - xpath: .//h3/a - attr: href - next_stage: "" - remark: "" - - name: abstract - css: "" - xpath: .//*[@class="c-abstract"] - attr: "" - next_stage: "" - remark: "" -settings: - ROBOTSTXT_OBEY: "false" - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, - like Gecko) Chrome/78.0.3904.108 Safari/537.36 diff --git a/backend/template/spiders/bing_general/Spiderfile b/backend/template/spiders/bing_general/Spiderfile deleted file mode 100644 index 614c135e..00000000 --- a/backend/template/spiders/bing_general/Spiderfile +++ /dev/null @@ -1,6 +0,0 @@ -name: "bing_general" -display_name: "必应搜索 (通用)" -remark: "必应搜索 Crawlab,列表+分页" -col: "results_bing_general" -type: "customized" -cmd: "python bing_spider.py" \ No newline at end of file diff --git a/backend/template/spiders/bing_general/bing_spider.py b/backend/template/spiders/bing_general/bing_spider.py deleted file mode 100644 index e982e4ee..00000000 --- a/backend/template/spiders/bing_general/bing_spider.py +++ /dev/null @@ -1,41 +0,0 @@ -import requests -from bs4 import BeautifulSoup as bs -from urllib.parse import urljoin, urlparse -import re -from crawlab import save_item - -s = requests.Session() - -def get_real_url(response, url): - if re.search(r'^https?', url): - return url - elif re.search(r'^\/\/', url): - u = urlparse(response.url) - return u.scheme + url - return urljoin(response.url, url) - -def start_requests(): - for i in range(0, 9): - fr = 'PERE' if not i else 'MORE' - url = f'https://cn.bing.com/search?q=crawlab&first={10 * i + 1}&FROM={fr}' - request_page(url) - -def request_page(url): - print(f'requesting {url}') - r = s.get(url, headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}) - parse_list(r) - -def parse_list(response): - soup = bs(response.content.decode('utf-8')) - for el in list(soup.select('#b_results > li')): - try: - save_item({ - 'title': el.select_one('h2').text, - 'url': el.select_one('h2 a').attrs.get('href'), - 'abstract': el.select_one('.b_caption p').text, - }) - except: - pass - -if __name__ == '__main__': - start_requests() \ No newline at end of file diff --git a/backend/template/spiders/chinaz/Spiderfile b/backend/template/spiders/chinaz/Spiderfile deleted file mode 100644 index 2fb940bb..00000000 --- a/backend/template/spiders/chinaz/Spiderfile +++ /dev/null @@ -1,5 +0,0 @@ -name: "chinaz" -display_name: "站长之家 (Scrapy)" -col: "results_chinaz" -type: "customized" -cmd: "scrapy crawl chinaz_spider" \ No newline at end of file diff --git a/backend/template/spiders/chinaz/chinaz/__init__.py b/backend/template/spiders/chinaz/chinaz/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/template/spiders/chinaz/chinaz/items.py b/backend/template/spiders/chinaz/chinaz/items.py deleted file mode 100644 index 1fdcac1b..00000000 --- a/backend/template/spiders/chinaz/chinaz/items.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your scraped items -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/items.html - -import scrapy - - -class ChinazItem(scrapy.Item): - # define the fields for your item here like: - _id = scrapy.Field() - task_id = scrapy.Field() - name = scrapy.Field() - domain = scrapy.Field() - description = scrapy.Field() - rank = scrapy.Field() - main_category = scrapy.Field() - category = scrapy.Field() - location = scrapy.Field() diff --git a/backend/template/spiders/chinaz/chinaz/middlewares.py b/backend/template/spiders/chinaz/chinaz/middlewares.py deleted file mode 100644 index c98995d5..00000000 --- a/backend/template/spiders/chinaz/chinaz/middlewares.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your spider middleware -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -from scrapy import signals - - -class ChinazSpiderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the spider middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_spider_input(self, response, spider): - # Called for each response that goes through the spider - # middleware and into the spider. - - # Should return None or raise an exception. - return None - - def process_spider_output(self, response, result, spider): - # Called with the results returned from the Spider, after - # it has processed the response. - - # Must return an iterable of Request, dict or Item objects. - for i in result: - yield i - - def process_spider_exception(self, response, exception, spider): - # Called when a spider or process_spider_input() method - # (from other spider middleware) raises an exception. - - # Should return either None or an iterable of Response, dict - # or Item objects. - pass - - def process_start_requests(self, start_requests, spider): - # Called with the start requests of the spider, and works - # similarly to the process_spider_output() method, except - # that it doesn’t have a response associated. - - # Must return only requests (not items). - for r in start_requests: - yield r - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) - - -class ChinazDownloaderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the downloader middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_request(self, request, spider): - # Called for each request that goes through the downloader - # middleware. - - # Must either: - # - return None: continue processing this request - # - or return a Response object - # - or return a Request object - # - or raise IgnoreRequest: process_exception() methods of - # installed downloader middleware will be called - return None - - def process_response(self, request, response, spider): - # Called with the response returned from the downloader. - - # Must either; - # - return a Response object - # - return a Request object - # - or raise IgnoreRequest - return response - - def process_exception(self, request, exception, spider): - # Called when a download handler or a process_request() - # (from other downloader middleware) raises an exception. - - # Must either: - # - return None: continue processing this exception - # - return a Response object: stops process_exception() chain - # - return a Request object: stops process_exception() chain - pass - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) diff --git a/backend/template/spiders/chinaz/chinaz/pipelines.py b/backend/template/spiders/chinaz/chinaz/pipelines.py deleted file mode 100644 index b29f9eb7..00000000 --- a/backend/template/spiders/chinaz/chinaz/pipelines.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define your item pipelines here -# -# Don't forget to add your pipeline to the ITEM_PIPELINES setting -# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html - diff --git a/backend/template/spiders/chinaz/chinaz/settings.py b/backend/template/spiders/chinaz/chinaz/settings.py deleted file mode 100644 index 932ec9ed..00000000 --- a/backend/template/spiders/chinaz/chinaz/settings.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- - -# Scrapy settings for chinaz project -# -# For simplicity, this file contains only settings considered important or -# commonly used. You can find more settings consulting the documentation: -# -# https://doc.scrapy.org/en/latest/topics/settings.html -# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -BOT_NAME = 'chinaz' - -SPIDER_MODULES = ['chinaz.spiders'] -NEWSPIDER_MODULE = 'chinaz.spiders' - - -# Crawl responsibly by identifying yourself (and your website) on the user-agent -#USER_AGENT = 'chinaz (+http://www.yourdomain.com)' - -# Obey robots.txt rules -ROBOTSTXT_OBEY = True - -# Configure maximum concurrent requests performed by Scrapy (default: 16) -#CONCURRENT_REQUESTS = 32 - -# Configure a delay for requests for the same website (default: 0) -# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay -# See also autothrottle settings and docs -#DOWNLOAD_DELAY = 3 -# The download delay setting will honor only one of: -#CONCURRENT_REQUESTS_PER_DOMAIN = 16 -#CONCURRENT_REQUESTS_PER_IP = 16 - -# Disable cookies (enabled by default) -#COOKIES_ENABLED = False - -# Disable Telnet Console (enabled by default) -#TELNETCONSOLE_ENABLED = False - -# Override the default request headers: -#DEFAULT_REQUEST_HEADERS = { -# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', -# 'Accept-Language': 'en', -#} - -# Enable or disable spider middlewares -# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html -#SPIDER_MIDDLEWARES = { -# 'chinaz.middlewares.ChinazSpiderMiddleware': 543, -#} - -# Enable or disable downloader middlewares -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -#DOWNLOADER_MIDDLEWARES = { -# 'chinaz.middlewares.ChinazDownloaderMiddleware': 543, -#} - -# Enable or disable extensions -# See https://doc.scrapy.org/en/latest/topics/extensions.html -#EXTENSIONS = { -# 'scrapy.extensions.telnet.TelnetConsole': None, -#} - -# Configure item pipelines -# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html -ITEM_PIPELINES = { - 'crawlab.pipelines.CrawlabMongoPipeline': 300, -} - -# Enable and configure the AutoThrottle extension (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/autothrottle.html -#AUTOTHROTTLE_ENABLED = True -# The initial download delay -#AUTOTHROTTLE_START_DELAY = 5 -# The maximum download delay to be set in case of high latencies -#AUTOTHROTTLE_MAX_DELAY = 60 -# The average number of requests Scrapy should be sending in parallel to -# each remote server -#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 -# Enable showing throttling stats for every response received: -#AUTOTHROTTLE_DEBUG = False - -# Enable and configure HTTP caching (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings -#HTTPCACHE_ENABLED = True -#HTTPCACHE_EXPIRATION_SECS = 0 -#HTTPCACHE_DIR = 'httpcache' -#HTTPCACHE_IGNORE_HTTP_CODES = [] -#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' diff --git a/backend/template/spiders/chinaz/chinaz/spiders/__init__.py b/backend/template/spiders/chinaz/chinaz/spiders/__init__.py deleted file mode 100644 index ebd689ac..00000000 --- a/backend/template/spiders/chinaz/chinaz/spiders/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# This package will contain the spiders of your Scrapy project -# -# Please refer to the documentation for information on how to create and manage -# your spiders. diff --git a/backend/template/spiders/chinaz/chinaz/spiders/chinaz_spider.py b/backend/template/spiders/chinaz/chinaz/spiders/chinaz_spider.py deleted file mode 100644 index 28ad84e7..00000000 --- a/backend/template/spiders/chinaz/chinaz/spiders/chinaz_spider.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- -import scrapy -from chinaz.items import ChinazItem - - -class ChinazSpiderSpider(scrapy.Spider): - name = 'chinaz_spider' - allowed_domains = ['chinaz.com'] - start_urls = ['http://top.chinaz.com/hangye/'] - - def parse(self, response): - for item in response.css('.listCentent > li'): - name = item.css('h3.rightTxtHead > a::text').extract_first() - href = item.css('h3.rightTxtHead > a::attr("href")').extract_first() - domain = item.css('h3.rightTxtHead > span::text').extract_first() - description = item.css('p.RtCInfo::text').extract_first() - rank = item.css('.RtCRateCent > strong::text').extract_first() - rank = int(rank) - item = ChinazItem( - _id=domain, - name=name, - domain=domain, - description=description, - rank=rank, - ) - yield scrapy.Request( - url='http://top.chinaz.com' + href, - callback=self.parse_item, - meta={ - 'item': item - } - ) - - # pagination - a_list = response.css('.ListPageWrap > a::attr("href")').extract() - url = 'http://top.chinaz.com/hangye/' + a_list[-1] - yield scrapy.Request(url=url, callback=self.parse) - - def parse_item(self, response): - item = response.meta['item'] - - # category info extraction - arr = response.css('.TopMainTag-show .SimSun') - res1 = arr[0].css('a::text').extract() - main_category = res1[0] - if len(res1) == 1: - category = '其他' - else: - category = res1[1] - - # location info extraction - res2 = arr[1].css('a::text').extract() - if len(res2) > 0: - location = res2[0] - else: - location = '其他' - - # assign values to item - item['main_category'] = main_category - item['category'] = category - item['location'] = location - - yield item diff --git a/backend/template/spiders/chinaz/scrapy.cfg b/backend/template/spiders/chinaz/scrapy.cfg deleted file mode 100644 index d3b44a1a..00000000 --- a/backend/template/spiders/chinaz/scrapy.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Automatically created by: scrapy startproject -# -# For more information about the [deploy] section see: -# https://scrapyd.readthedocs.io/en/latest/deploy.html - -[settings] -default = chinaz.settings - -[deploy] -#url = http://localhost:6800/ -project = chinaz diff --git a/backend/template/spiders/csdn/csdn_spider.js b/backend/template/spiders/csdn/csdn_spider.js deleted file mode 100644 index 0f65c0ad..00000000 --- a/backend/template/spiders/csdn/csdn_spider.js +++ /dev/null @@ -1,87 +0,0 @@ -const puppeteer = require('puppeteer'); -const MongoClient = require('mongodb').MongoClient; - -const MONGO_HOST = process.env.MONGO_HOST; -const MONGO_PORT = process.env.MONGO_PORT; -const MONGO_DB = process.env.MONGO_DB; - -(async () => { - // browser - const browser = await (puppeteer.launch({ - headless: true - })); - - // define start url - const url = 'https://www.csdn.net'; - - // start a new page - const page = await browser.newPage(); - - // navigate to url - try { - await page.goto(url, {waitUntil: 'domcontentloaded'}); - await page.waitFor(2000); - } catch (e) { - console.error(e); - - // close browser - browser.close(); - - // exit code 1 indicating an error happened - code = 1; - process.emit("exit "); - process.reallyExit(code); - - return - } - - // scroll down to fetch more data - for (let i = 0; i < 100; i++) { - console.log('Pressing PageDown...'); - await page.keyboard.press('PageDown', 200); - await page.waitFor(100); - } - - // scrape data - const results = await page.evaluate(() => { - let results = []; - document.querySelectorAll('#feedlist_id > li').forEach(el => { - const $a = el.querySelector('.title > h2 > a'); - if (!$a) return; - results.push({ - url: $a.getAttribute('href'), - title: $a.innerText - }); - }); - return results; - }); - - // open database connection - const client = await MongoClient.connect(`mongodb://${MONGO_HOST}:${MONGO_PORT}`); - let db = await client.db(MONGO_DB); - const colName = process.env.CRAWLAB_COLLECTION || 'results_juejin'; - const taskId = process.env.CRAWLAB_TASK_ID; - const col = db.collection(colName); - - // save to database - for (let i = 0; i < results.length; i++) { - // de-duplication - const r = await col.findOne({url: results[i]}); - if (r) continue; - - // assign taskID - results[i].task_id = taskId; - results[i].source = 'csdn'; - - // insert row - await col.insertOne(results[i]); - } - - console.log(`results.length: ${results.length}`); - - // close database connection - client.close(); - - // shutdown browser - browser.close(); -})(); \ No newline at end of file diff --git a/backend/template/spiders/csdn_config/Spiderfile b/backend/template/spiders/csdn_config/Spiderfile deleted file mode 100644 index 67f4f8c5..00000000 --- a/backend/template/spiders/csdn_config/Spiderfile +++ /dev/null @@ -1,60 +0,0 @@ -name: "csdn_config" -display_name: "CSDN(可配置)" -remark: "CSDN Crawlab 文章,列表+详情+分页" -type: "configurable" -col: "results_csdn_config" -engine: scrapy -start_url: https://so.csdn.net/so/search/s.do?q=crawlab -start_stage: list -stages: -- name: list - is_list: true - list_css: .search-list-con > .search-list - list_xpath: "" - page_css: a.btn-next - page_xpath: "" - page_attr: href - fields: - - name: url - css: "" - xpath: .//*[@class="limit_width"]/a - attr: href - next_stage: detail - remark: "" -- name: detail - is_list: false - list_css: "" - list_xpath: "" - page_css: "" - page_xpath: "" - page_attr: "" - fields: - - name: content - css: "" - xpath: .//div[@id="content_views"] - attr: "" - next_stage: "" - remark: "" - - name: views - css: .read-count - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: title - css: .title-article - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: author - css: .follow-nickName - xpath: "" - attr: "" - next_stage: "" - remark: "" -settings: - AUTOTHROTTLE_ENABLED: "false" - ROBOTSTXT_OBEY: "false" - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, - like Gecko) Chrome/79.0.3945.117 Safari/537.36 diff --git a/backend/template/spiders/douban_config/Spiderfile b/backend/template/spiders/douban_config/Spiderfile deleted file mode 100644 index 84f0647a..00000000 --- a/backend/template/spiders/douban_config/Spiderfile +++ /dev/null @@ -1,57 +0,0 @@ -name: "douban_config" -display_name: "豆瓣读书(可配置)" -remark: "豆瓣读书新书推荐,列表" -type: "configurable" -col: "results_douban_config" -engine: scrapy -start_url: https://book.douban.com/latest -start_stage: list -stages: -- name: list - is_list: true - list_css: ul.cover-col-4 > li - list_xpath: "" - page_css: "" - page_xpath: "" - page_attr: "" - fields: - - name: title - css: h2 > a - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: url - css: h2 > a - xpath: "" - attr: href - next_stage: "" - remark: "" - - name: img - css: a.cover img - xpath: "" - attr: src - next_stage: "" - remark: "" - - name: rating - css: p.rating > .color-lightgray - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: abstract - css: p:last-child - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: info - css: .color-gray - xpath: "" - attr: "" - next_stage: "" - remark: "" -settings: - ROBOTSTXT_OBEY: "false" - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, - like Gecko) Chrome/78.0.3904.108 Safari/537.36 diff --git a/backend/template/spiders/jd/Spiderfile b/backend/template/spiders/jd/Spiderfile deleted file mode 100644 index d090472b..00000000 --- a/backend/template/spiders/jd/Spiderfile +++ /dev/null @@ -1,5 +0,0 @@ -name: "jd" -display_name: "京东 (Scrapy)" -col: "results_jd" -type: "customized" -cmd: "scrapy crawl jd_spider" \ No newline at end of file diff --git a/backend/template/spiders/jd/jd/__init__.py b/backend/template/spiders/jd/jd/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/template/spiders/jd/jd/items.py b/backend/template/spiders/jd/jd/items.py deleted file mode 100644 index b2c5e647..00000000 --- a/backend/template/spiders/jd/jd/items.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your scraped items -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/items.html - -import scrapy - - -class JdItem(scrapy.Item): - # define the fields for your item here like: - name = scrapy.Field() - price = scrapy.Field() - url = scrapy.Field() diff --git a/backend/template/spiders/jd/jd/middlewares.py b/backend/template/spiders/jd/jd/middlewares.py deleted file mode 100644 index 6fceded5..00000000 --- a/backend/template/spiders/jd/jd/middlewares.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your spider middleware -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -from scrapy import signals - - -class JdSpiderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the spider middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_spider_input(self, response, spider): - # Called for each response that goes through the spider - # middleware and into the spider. - - # Should return None or raise an exception. - return None - - def process_spider_output(self, response, result, spider): - # Called with the results returned from the Spider, after - # it has processed the response. - - # Must return an iterable of Request, dict or Item objects. - for i in result: - yield i - - def process_spider_exception(self, response, exception, spider): - # Called when a spider or process_spider_input() method - # (from other spider middleware) raises an exception. - - # Should return either None or an iterable of Response, dict - # or Item objects. - pass - - def process_start_requests(self, start_requests, spider): - # Called with the start requests of the spider, and works - # similarly to the process_spider_output() method, except - # that it doesn’t have a response associated. - - # Must return only requests (not items). - for r in start_requests: - yield r - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) - - -class JdDownloaderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the downloader middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_request(self, request, spider): - # Called for each request that goes through the downloader - # middleware. - - # Must either: - # - return None: continue processing this request - # - or return a Response object - # - or return a Request object - # - or raise IgnoreRequest: process_exception() methods of - # installed downloader middleware will be called - return None - - def process_response(self, request, response, spider): - # Called with the response returned from the downloader. - - # Must either; - # - return a Response object - # - return a Request object - # - or raise IgnoreRequest - return response - - def process_exception(self, request, exception, spider): - # Called when a download handler or a process_request() - # (from other downloader middleware) raises an exception. - - # Must either: - # - return None: continue processing this exception - # - return a Response object: stops process_exception() chain - # - return a Request object: stops process_exception() chain - pass - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) diff --git a/backend/template/spiders/jd/jd/pipelines.py b/backend/template/spiders/jd/jd/pipelines.py deleted file mode 100644 index 5a7d7cbf..00000000 --- a/backend/template/spiders/jd/jd/pipelines.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define your item pipelines here -# -# Don't forget to add your pipeline to the ITEM_PIPELINES setting -# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html diff --git a/backend/template/spiders/jd/jd/settings.py b/backend/template/spiders/jd/jd/settings.py deleted file mode 100644 index ef89ed0c..00000000 --- a/backend/template/spiders/jd/jd/settings.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- - -# Scrapy settings for jd project -# -# For simplicity, this file contains only settings considered important or -# commonly used. You can find more settings consulting the documentation: -# -# https://doc.scrapy.org/en/latest/topics/settings.html -# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -BOT_NAME = 'jd' - -SPIDER_MODULES = ['jd.spiders'] -NEWSPIDER_MODULE = 'jd.spiders' - - -# Crawl responsibly by identifying yourself (and your website) on the user-agent -#USER_AGENT = 'jd (+http://www.yourdomain.com)' - -# Obey robots.txt rules -ROBOTSTXT_OBEY = False - -# Configure maximum concurrent requests performed by Scrapy (default: 16) -#CONCURRENT_REQUESTS = 32 - -# Configure a delay for requests for the same website (default: 0) -# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay -# See also autothrottle settings and docs -#DOWNLOAD_DELAY = 3 -# The download delay setting will honor only one of: -#CONCURRENT_REQUESTS_PER_DOMAIN = 16 -#CONCURRENT_REQUESTS_PER_IP = 16 - -# Disable cookies (enabled by default) -#COOKIES_ENABLED = False - -# Disable Telnet Console (enabled by default) -#TELNETCONSOLE_ENABLED = False - -# Override the default request headers: -#DEFAULT_REQUEST_HEADERS = { -# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', -# 'Accept-Language': 'en', -#} - -# Enable or disable spider middlewares -# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html -#SPIDER_MIDDLEWARES = { -# 'jd.middlewares.JdSpiderMiddleware': 543, -#} - -# Enable or disable downloader middlewares -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -#DOWNLOADER_MIDDLEWARES = { -# 'jd.middlewares.JdDownloaderMiddleware': 543, -#} - -# Enable or disable extensions -# See https://doc.scrapy.org/en/latest/topics/extensions.html -#EXTENSIONS = { -# 'scrapy.extensions.telnet.TelnetConsole': None, -#} - -# Configure item pipelines -# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html -ITEM_PIPELINES = { - 'crawlab.pipelines.CrawlabMongoPipeline': 300, -} - -# Enable and configure the AutoThrottle extension (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/autothrottle.html -#AUTOTHROTTLE_ENABLED = True -# The initial download delay -#AUTOTHROTTLE_START_DELAY = 5 -# The maximum download delay to be set in case of high latencies -#AUTOTHROTTLE_MAX_DELAY = 60 -# The average number of requests Scrapy should be sending in parallel to -# each remote server -#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 -# Enable showing throttling stats for every response received: -#AUTOTHROTTLE_DEBUG = False - -# Enable and configure HTTP caching (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings -#HTTPCACHE_ENABLED = True -#HTTPCACHE_EXPIRATION_SECS = 0 -#HTTPCACHE_DIR = 'httpcache' -#HTTPCACHE_IGNORE_HTTP_CODES = [] -#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' diff --git a/backend/template/spiders/jd/jd/spiders/__init__.py b/backend/template/spiders/jd/jd/spiders/__init__.py deleted file mode 100644 index ebd689ac..00000000 --- a/backend/template/spiders/jd/jd/spiders/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# This package will contain the spiders of your Scrapy project -# -# Please refer to the documentation for information on how to create and manage -# your spiders. diff --git a/backend/template/spiders/jd/jd/spiders/jd_spider.py b/backend/template/spiders/jd/jd/spiders/jd_spider.py deleted file mode 100644 index 4ec94fa9..00000000 --- a/backend/template/spiders/jd/jd/spiders/jd_spider.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -import scrapy - -from jd.items import JdItem - - -class JdSpiderSpider(scrapy.Spider): - name = 'jd_spider' - allowed_domains = ['jd.com'] - - def start_requests(self): - for i in range(1, 50): - yield scrapy.Request(url=f'https://search.jd.com/Search?keyword=手机&enc=utf-8&page={i}') - - def parse(self, response): - for el in response.css('.gl-item'): - yield JdItem( - url=el.css('.p-name > a::attr("href")').extract_first(), - name=el.css('.p-name > a::attr("title")').extract_first(), - price=float(el.css('.p-price i::text').extract_first()), - ) diff --git a/backend/template/spiders/jd/scrapy.cfg b/backend/template/spiders/jd/scrapy.cfg deleted file mode 100644 index 87cf0280..00000000 --- a/backend/template/spiders/jd/scrapy.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Automatically created by: scrapy startproject -# -# For more information about the [deploy] section see: -# https://scrapyd.readthedocs.io/en/latest/deploy.html - -[settings] -default = jd.settings - -[deploy] -#url = http://localhost:6800/ -project = jd diff --git a/backend/template/spiders/jd_mask/Spiderfile b/backend/template/spiders/jd_mask/Spiderfile deleted file mode 100644 index b5134646..00000000 --- a/backend/template/spiders/jd_mask/Spiderfile +++ /dev/null @@ -1,5 +0,0 @@ -name: "jd_mask" -display_name: "京东口罩 (Puppeteer)" -col: "results_jd" -type: "customized" -cmd: "dumb-init -- node jd_mask_spider.js" \ No newline at end of file diff --git a/backend/template/spiders/jd_mask/jd_mask_spider.js b/backend/template/spiders/jd_mask/jd_mask_spider.js deleted file mode 100644 index dfa5c808..00000000 --- a/backend/template/spiders/jd_mask/jd_mask_spider.js +++ /dev/null @@ -1,84 +0,0 @@ -const crawlab = require('crawlab-sdk'); -const PCR = require('puppeteer-chromium-resolver'); - -const crawlDetail = async (page, url) => { - await page.goto(url); - await page.waitForSelector('#choose-btns'); - await page.waitFor(500); - - const hasStock = await page.evaluate(() => { - return !document.querySelector('.J-notify-stock'); - }); - return hasStock; -}; - -const crawlPage = async (page) => { - const items = await page.evaluate(() => { - const items = []; - document.querySelectorAll('.gl-item').forEach(el => { - items.push({ - title: el.querySelector('.p-name > a').getAttribute('title'), - url: 'https:' + el.querySelector('.p-name > a').getAttribute('href'), - }); - }); - return items; - }); - - for (let i = 0; i < items.length; i++) { - const item = items[i]; - item['has_stock'] = await crawlDetail(page, item.url); - await crawlab.saveItem(item); - } - - await page.waitFor(1000); -}; - -const main = async () => { - const pcr = await PCR({ - folderName: '.chromium-browser-snapshots', - hosts: ["https://storage.googleapis.com", "https://npm.taobao.org/mirrors"], - retry: 3 - }); - - const browser = await pcr.puppeteer.launch({ - headless: true, - args: ['--no-sandbox'], - executablePath: pcr.executablePath - }).catch(function (error) { - console.log(error); - }); - - const page = await browser.newPage(); - - await page.goto('https://www.jd.com/chanpin/270170.html'); - await page.waitForSelector('#J_goodsList'); - await page.waitFor(1000); - - await crawlPage(page); - - while (true) { - const hasNext = await page.evaluate(() => { - if (!document.querySelector('.pn-next')) return false - return !document.querySelector('.pn-next.disabled') - }); - - if (!hasNext) break; - - await page.click('.pn-next'); - await page.waitFor(1000); - await crawlPage(page); - } - - await browser.close(); -}; - -(async () => { - try { - await main() - } catch (e) { - console.error(e) - } - - await crawlab.close(); - // process.exit(); -})(); \ No newline at end of file diff --git a/backend/template/spiders/juejin_node/juejin_spider.js b/backend/template/spiders/juejin_node/juejin_spider.js deleted file mode 100644 index afb0cea8..00000000 --- a/backend/template/spiders/juejin_node/juejin_spider.js +++ /dev/null @@ -1,84 +0,0 @@ -const puppeteer = require('puppeteer'); -const MongoClient = require('mongodb').MongoClient; - -(async () => { - // browser - const browser = await (puppeteer.launch({ - headless: true - })); - - // define start url - const url = 'https://juejin.im'; - - // start a new page - const page = await browser.newPage(); - - // navigate to url - try { - await page.goto(url, {waitUntil: 'domcontentloaded'}); - await page.waitFor(2000); - } catch (e) { - console.error(e); - - // close browser - browser.close(); - - // exit code 1 indicating an error happened - code = 1; - process.emit("exit "); - process.reallyExit(code); - - return - } - - // scroll down to fetch more data - for (let i = 0; i < 100; i++) { - console.log('Pressing PageDown...'); - await page.keyboard.press('PageDown', 200); - await page.waitFor(100); - } - - // scrape data - const results = await page.evaluate(() => { - let results = []; - document.querySelectorAll('.entry-list > .item').forEach(el => { - if (!el.querySelector('.title')) return; - results.push({ - url: 'https://juejin.com' + el.querySelector('.title').getAttribute('href'), - title: el.querySelector('.title').innerText - }); - }); - return results; - }); - - // open database connection - console.log(process.env.MONGO_HOST); - console.log(process.env.MONGO_PORT); - const client = await MongoClient.connect(`mongodb://${process.env.MONGO_HOST}:${process.env.MONGO_PORT}`); - let db = await client.db(process.env.MONGO_DB); - const colName = process.env.CRAWLAB_COLLECTION || 'results_juejin'; - const taskId = process.env.CRAWLAB_TASK_ID; - const col = db.collection(colName); - - // save to database - for (let i = 0; i < results.length; i++) { - // de-duplication - const r = await col.findOne({url: results[i]}); - if (r) continue; - - // assign taskID - results[i].task_id = taskId; - results[i].source = 'juejin'; - - // insert row - await col.insertOne(results[i]); - } - - console.log(`results.length: ${results.length}`); - - // close database connection - client.close(); - - // shutdown browser - browser.close(); -})(); \ No newline at end of file diff --git a/backend/template/spiders/realestate/Spiderfile b/backend/template/spiders/realestate/Spiderfile deleted file mode 100644 index 772e8312..00000000 --- a/backend/template/spiders/realestate/Spiderfile +++ /dev/null @@ -1,4 +0,0 @@ -name: "realestate" -display_name: "链家网 (Scrapy)" -col: "results_realestate" -cmd: "scrapy crawl lianjia" \ No newline at end of file diff --git a/backend/template/spiders/realestate/realestate/__init__.py b/backend/template/spiders/realestate/realestate/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/template/spiders/realestate/realestate/items.py b/backend/template/spiders/realestate/realestate/items.py deleted file mode 100644 index 189b92ed..00000000 --- a/backend/template/spiders/realestate/realestate/items.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your scraped items -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/items.html - -import scrapy - - -class RealEstateItem(scrapy.Item): - # _id - _id = scrapy.Field() - - # task_id - task_id = scrapy.Field() - - # 房产名 - name = scrapy.Field() - - # url - url = scrapy.Field() - - # 类别 - type = scrapy.Field() - - # 价格(万) - price = scrapy.Field() - - # 大小 - size = scrapy.Field() - - # 小区 - region = scrapy.Field() - - # 城市 - city = scrapy.Field() diff --git a/backend/template/spiders/realestate/realestate/middlewares.py b/backend/template/spiders/realestate/realestate/middlewares.py deleted file mode 100644 index ed845f57..00000000 --- a/backend/template/spiders/realestate/realestate/middlewares.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your spider middleware -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -from scrapy import signals - - -class RealestateSpiderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the spider middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_spider_input(self, response, spider): - # Called for each response that goes through the spider - # middleware and into the spider. - - # Should return None or raise an exception. - return None - - def process_spider_output(self, response, result, spider): - # Called with the results returned from the Spider, after - # it has processed the response. - - # Must return an iterable of Request, dict or Item objects. - for i in result: - yield i - - def process_spider_exception(self, response, exception, spider): - # Called when a spider or process_spider_input() method - # (from other spider middleware) raises an exception. - - # Should return either None or an iterable of Response, dict - # or Item objects. - pass - - def process_start_requests(self, start_requests, spider): - # Called with the start requests of the spider, and works - # similarly to the process_spider_output() method, except - # that it doesn’t have a response associated. - - # Must return only requests (not items). - for r in start_requests: - yield r - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) - - -class RealestateDownloaderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the downloader middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_request(self, request, spider): - # Called for each request that goes through the downloader - # middleware. - - # Must either: - # - return None: continue processing this request - # - or return a Response object - # - or return a Request object - # - or raise IgnoreRequest: process_exception() methods of - # installed downloader middleware will be called - return None - - def process_response(self, request, response, spider): - # Called with the response returned from the downloader. - - # Must either; - # - return a Response object - # - return a Request object - # - or raise IgnoreRequest - return response - - def process_exception(self, request, exception, spider): - # Called when a download handler or a process_request() - # (from other downloader middleware) raises an exception. - - # Must either: - # - return None: continue processing this exception - # - return a Response object: stops process_exception() chain - # - return a Request object: stops process_exception() chain - pass - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) diff --git a/backend/template/spiders/realestate/realestate/pipelines.py b/backend/template/spiders/realestate/realestate/pipelines.py deleted file mode 100644 index 3371792b..00000000 --- a/backend/template/spiders/realestate/realestate/pipelines.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define your item pipelines here -# -# Don't forget to add your pipeline to the ITEM_PIPELINES setting -# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html diff --git a/backend/template/spiders/realestate/realestate/settings.py b/backend/template/spiders/realestate/realestate/settings.py deleted file mode 100644 index 758f8ed0..00000000 --- a/backend/template/spiders/realestate/realestate/settings.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- - -# Scrapy settings for realestate project -# -# For simplicity, this file contains only settings considered important or -# commonly used. You can find more settings consulting the documentation: -# -# https://doc.scrapy.org/en/latest/topics/settings.html -# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -BOT_NAME = 'realestate' - -SPIDER_MODULES = ['realestate.spiders'] -NEWSPIDER_MODULE = 'realestate.spiders' - -# Crawl responsibly by identifying yourself (and your website) on the user-agent -# USER_AGENT = 'realestate (+http://www.yourdomain.com)' - -# Obey robots.txt rules -ROBOTSTXT_OBEY = True - -# Configure maximum concurrent requests performed by Scrapy (default: 16) -# CONCURRENT_REQUESTS = 32 - -# Configure a delay for requests for the same website (default: 0) -# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay -# See also autothrottle settings and docs -# DOWNLOAD_DELAY = 3 -# The download delay setting will honor only one of: -# CONCURRENT_REQUESTS_PER_DOMAIN = 16 -# CONCURRENT_REQUESTS_PER_IP = 16 - -# Disable cookies (enabled by default) -# COOKIES_ENABLED = False - -# Disable Telnet Console (enabled by default) -# TELNETCONSOLE_ENABLED = False - -# Override the default request headers: -# DEFAULT_REQUEST_HEADERS = { -# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', -# 'Accept-Language': 'en', -# } - -# Enable or disable spider middlewares -# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html -# SPIDER_MIDDLEWARES = { -# 'realestate.middlewares.RealestateSpiderMiddleware': 543, -# } - -# Enable or disable downloader middlewares -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -# DOWNLOADER_MIDDLEWARES = { -# 'realestate.middlewares.RealestateDownloaderMiddleware': 543, -# } - -# Enable or disable extensions -# See https://doc.scrapy.org/en/latest/topics/extensions.html -# EXTENSIONS = { -# 'scrapy.extensions.telnet.TelnetConsole': None, -# } - -# Configure item pipelines -# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html -ITEM_PIPELINES = { - 'crawlab.pipelines.CrawlabMongoPipeline': 300, -} - -# Enable and configure the AutoThrottle extension (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/autothrottle.html -# AUTOTHROTTLE_ENABLED = True -# The initial download delay -# AUTOTHROTTLE_START_DELAY = 5 -# The maximum download delay to be set in case of high latencies -# AUTOTHROTTLE_MAX_DELAY = 60 -# The average number of requests Scrapy should be sending in parallel to -# each remote server -# AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 -# Enable showing throttling stats for every response received: -# AUTOTHROTTLE_DEBUG = False - -# Enable and configure HTTP caching (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings -# HTTPCACHE_ENABLED = True -# HTTPCACHE_EXPIRATION_SECS = 0 -# HTTPCACHE_DIR = 'httpcache' -# HTTPCACHE_IGNORE_HTTP_CODES = [] -# HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' diff --git a/backend/template/spiders/realestate/realestate/spiders/__init__.py b/backend/template/spiders/realestate/realestate/spiders/__init__.py deleted file mode 100644 index ebd689ac..00000000 --- a/backend/template/spiders/realestate/realestate/spiders/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# This package will contain the spiders of your Scrapy project -# -# Please refer to the documentation for information on how to create and manage -# your spiders. diff --git a/backend/template/spiders/realestate/realestate/spiders/lianjia.py b/backend/template/spiders/realestate/realestate/spiders/lianjia.py deleted file mode 100644 index cad054f3..00000000 --- a/backend/template/spiders/realestate/realestate/spiders/lianjia.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -import scrapy - -from realestate.items import RealEstateItem - - -class LianjiaSpider(scrapy.Spider): - name = 'lianjia' - allowed_domains = ['lianjia.com'] - start_urls = ['https://cq.lianjia.com/ershoufang/'] - - def start_requests(self): - for i in range(100): - url = 'https://cq.lianjia.com/ershoufang/pg%s' % i - yield scrapy.Request(url=url) - - def parse(self, response): - for item in response.css('.sellListContent > li'): - yield RealEstateItem( - name=item.css('.title > a::text').extract_first(), - url=item.css('.title > a::attr("href")').extract_first(), - type='secondhand', - price=item.css('.totalPrice > span::text').extract_first(), - region=item.css('.houseInfo > a::text').extract_first(), - size=item.css('.houseInfo::text').extract_first().split(' | ')[2] - ) - - # 分页 - # a_next = response.css('.house-lst-page-box > a')[-1] - # href = a_next.css('a::attr("href")') - # yield scrapy.Response(url='https://cq.lianjia.com' + href) diff --git a/backend/template/spiders/realestate/scrapy.cfg b/backend/template/spiders/realestate/scrapy.cfg deleted file mode 100644 index d630e123..00000000 --- a/backend/template/spiders/realestate/scrapy.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Automatically created by: scrapy startproject -# -# For more information about the [deploy] section see: -# https://scrapyd.readthedocs.io/en/latest/deploy.html - -[settings] -default = realestate.settings - -[deploy] -#url = http://localhost:6800/ -project = realestate diff --git a/backend/template/spiders/segmentfault/segmentfault_spider.js b/backend/template/spiders/segmentfault/segmentfault_spider.js deleted file mode 100644 index 834b61cc..00000000 --- a/backend/template/spiders/segmentfault/segmentfault_spider.js +++ /dev/null @@ -1,81 +0,0 @@ -const puppeteer = require('puppeteer'); -const MongoClient = require('mongodb').MongoClient; - -(async () => { - // browser - const browser = await (puppeteer.launch({ - headless: true - })); - - // define start url - const url = 'https://segmentfault.com/newest'; - - // start a new page - const page = await browser.newPage(); - - // navigate to url - try { - await page.goto(url, {waitUntil: 'domcontentloaded'}); - await page.waitFor(2000); - } catch (e) { - console.error(e); - - // close browser - browser.close(); - - // exit code 1 indicating an error happened - code = 1; - process.emit("exit "); - process.reallyExit(code); - - return - } - - // scroll down to fetch more data - for (let i = 0; i < 10; i++) { - console.log('Pressing PageDown...'); - await page.keyboard.press('PageDown', 200); - await page.waitFor(500); - } - - // scrape data - const results = await page.evaluate(() => { - let results = []; - document.querySelectorAll('.news-list .news-item').forEach(el => { - results.push({ - url: 'https://segmentfault.com' + el.querySelector('.news__item-info > a').getAttribute('href'), - title: el.querySelector('.news__item-title').innerText - }) - }); - return results; - }); - - // open database connection - const client = await MongoClient.connect('mongodb://127.0.0.1:27017'); - let db = await client.db('crawlab_test'); - const colName = process.env.CRAWLAB_COLLECTION || 'results_segmentfault'; - const taskId = process.env.CRAWLAB_TASK_ID; - const col = db.collection(colName); - - // save to database - for (let i = 0; i < results.length; i++) { - // de-duplication - const r = await col.findOne({url: results[i]}); - if (r) continue; - - // assign taskID - results[i].task_id = taskId; - results[i].source = 'segmentfault'; - - // insert row - await col.insertOne(results[i]); - } - - console.log(`results.length: ${results.length}`); - - // close database connection - client.close(); - - // shutdown browser - browser.close(); -})(); \ No newline at end of file diff --git a/backend/template/spiders/segmentfault_colly/.crawlabignore b/backend/template/spiders/segmentfault_colly/.crawlabignore deleted file mode 100644 index ae09aba9..00000000 --- a/backend/template/spiders/segmentfault_colly/.crawlabignore +++ /dev/null @@ -1,2 +0,0 @@ -vendor/ -.idea \ No newline at end of file diff --git a/backend/template/spiders/segmentfault_colly/go.mod b/backend/template/spiders/segmentfault_colly/go.mod deleted file mode 100644 index 4a6b6a1d..00000000 --- a/backend/template/spiders/segmentfault_colly/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module baidu_colly - -go 1.13 - -require ( - github.com/apex/log v1.8.0 - github.com/crawlab-team/crawlab-go-sdk v0.0.6 - github.com/gocolly/colly/v2 v2.1.0 -) diff --git a/backend/template/spiders/segmentfault_colly/go.sum b/backend/template/spiders/segmentfault_colly/go.sum deleted file mode 100644 index 32abde28..00000000 --- a/backend/template/spiders/segmentfault_colly/go.sum +++ /dev/null @@ -1,454 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= -github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE= -github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= -github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M= -github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0= -github.com/antchfx/xmlquery v1.2.4 h1:T/SH1bYdzdjTMoz2RgsfVKbM5uWh3gjDYYepFqQmFv4= -github.com/antchfx/xmlquery v1.2.4/go.mod h1:KQQuESaxSlqugE2ZBcM/qn+ebIpt+d+4Xx7YcSGAIrM= -github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= -github.com/antchfx/xpath v1.1.8 h1:PcL6bIX42Px5usSx6xRYw/wjB3wYGkj0MJ9MBzEKVgk= -github.com/antchfx/xpath v1.1.8/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= -github.com/apex/log v1.1.4 h1:3Zk+boorIQAAGBrHn0JUtAau4ihMamT4WdnfdnXM1zQ= -github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= -github.com/apex/log v1.8.0 h1:+W4j+dttibFvynPLlctdnYFUn1eLKT37BZWWW2iMfEM= -github.com/apex/log v1.8.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= -github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= -github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= -github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= -github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.33.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/crawlab-team/crawlab-go-sdk v0.0.0-20200811085947-8f8e907c6721 h1:K4WiBL6ygGdH/cw4XH68kylZ40hvW7QvGfW4r3DI75s= -github.com/crawlab-team/crawlab-go-sdk v0.0.1 h1:sHnjUEo5rf+WpyIuinabkHX716GFIjIzlgMlAUS3yZ8= -github.com/crawlab-team/crawlab-go-sdk v0.0.1/go.mod h1:o8G5GycvFLpN2JAFKARnc1sPP9cVl4UL/henjBuU/m0= -github.com/crawlab-team/crawlab-go-sdk v0.0.2 h1:5vC+EXSw6ugNp7KUFyakvXLkMrhuc+iwi6Wg54FzlIM= -github.com/crawlab-team/crawlab-go-sdk v0.0.2/go.mod h1:o8G5GycvFLpN2JAFKARnc1sPP9cVl4UL/henjBuU/m0= -github.com/crawlab-team/crawlab-go-sdk v0.0.3 h1:xtXPvAfrFInqHMQTc9z/4I4x3UD3MlKab3kxuJUlwIw= -github.com/crawlab-team/crawlab-go-sdk v0.0.3/go.mod h1:o8G5GycvFLpN2JAFKARnc1sPP9cVl4UL/henjBuU/m0= -github.com/crawlab-team/crawlab-go-sdk v0.0.5 h1:dpKEIMIwuAUTV+0ieow8QAGixrQKnslSfHrejBm/hOk= -github.com/crawlab-team/crawlab-go-sdk v0.0.5/go.mod h1:T462oNoHharqpV+d6mHORzxCTXx85nZUAnjRl4y2X9Y= -github.com/crawlab-team/crawlab-go-sdk v0.3.3 h1:AfnpbX8284bju/EDQlncnIlj6OAeeLz2zSKL+XSoxCA= -github.com/crawlab-team/crawlab-go-sdk v0.3.3/go.mod h1:o8G5GycvFLpN2JAFKARnc1sPP9cVl4UL/henjBuU/m0= -github.com/crawlab-team/crawlab-sdk v0.3.3 h1:wIZULN0tthEYN5rm4udC4lvNmYWUCVcIpjo8eOEAiUY= -github.com/crawlab-team/crawlab-sdk v0.3.3/go.mod h1:y/eYHfi/RRp1LZnjo8FGJxiCggksP0L48LSO3lHD0Mg= -github.com/crawlab-team/crawlab-sdk/go v0.0.0-20200811075433-4eb89aae4128 h1:pwPIhttJXHHLiz1ycsOCZvvYjq7DRPpwsCEJVv4BW0Y= -github.com/crawlab-team/crawlab-sdk/go v0.0.0-20200811081137-f170fe114b4f h1:UApT42/LRc2uukQPMNLXvdcSqcY9FofZmSeMPkf1UXg= -github.com/crawlab-team/crawlab-sdk/go v0.0.0-20200811081137-f170fe114b4f/go.mod h1:KdyXPWGLgPCkCBnz5SvZS+7u0V7thpdRo81x3iyNAqo= -github.com/crawlab-team/crawlab-sdk/go v0.0.0-20200811083544-41a4b61941df h1:x5CV/x5QoagYlkfGgyCNISjlu87sev47gf+J0zEqofk= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gocolly/colly v1.2.0 h1:qRz9YAn8FIH0qzgNUw+HT9UN7wm1oF9OBAilwEWpyrI= -github.com/gocolly/colly v1.2.0/go.mod h1:Hof5T3ZswNVsOHYmba1u03W65HDWgpV5HifSuueE0EA= -github.com/gocolly/colly/v2 v2.1.0 h1:k0DuZkDoCsx51bKpRJNEmcxcp+W5N8ziuwGaSDuFoGs= -github.com/gocolly/colly/v2 v2.1.0/go.mod h1:I2MuhsLjQ+Ex+IzK3afNS8/1qP3AedHOusRPcRdC5o0= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jawher/mow.cli v1.1.0/go.mod h1:aNaQlc7ozF3vw6IJ2dHjp2ZFiA4ozMIYY6PyuRJwlUg= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= -github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o= -github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.9.8 h1:VMAMUUOh+gaxKTMk+zqbjsSjsIcUcL/LF4o63i82QyA= -github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= -github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olivere/elastic/v7 v7.0.19 h1:w4F6JpqOISadhYf/n0NR1cNj73xHqh4pzPwD1Gkidts= -github.com/olivere/elastic/v7 v7.0.19/go.mod h1:4Jqt5xvjqpjCqgnTcHwl3j8TLs8mvoOK8NYgo/qEOu4= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= -github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/segmentio/kafka-go v0.4.1 h1:jyGn8DlpqI5iPArVxQj6o1IqPk76A+VN3JkhTkDr2Mo= -github.com/segmentio/kafka-go v0.4.1/go.mod h1:Inh7PqOsxmfgasV8InZYKVXWsdjcCq2d9tFV75GLbuM= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= -github.com/smartystreets/gunit v1.3.4/go.mod h1:ZjM1ozSIMJlAz/ay4SG8PeKF00ckUp+zMHZXV9/bvak= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/temoto/robotstxt v1.1.1 h1:Gh8RCs8ouX3hRSxxK7B1mO5RFByQ4CmJZDwgom++JaA= -github.com/temoto/robotstxt v1.1.1/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo= -github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= -github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= -github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= -github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= -github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= -github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= -github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/backend/template/spiders/segmentfault_colly/main.go b/backend/template/spiders/segmentfault_colly/main.go deleted file mode 100644 index c6eff3ad..00000000 --- a/backend/template/spiders/segmentfault_colly/main.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "fmt" - "github.com/apex/log" - "github.com/crawlab-team/crawlab-go-sdk" - "github.com/crawlab-team/crawlab-go-sdk/entity" - "github.com/gocolly/colly/v2" - "runtime/debug" -) - -func main() { - startUrl := "https://segmentfault.com/search?q=crawlab" - - c := colly.NewCollector( - colly.Async(true), - colly.UserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"), - ) - - c.OnHTML(".search-result > .widget-blog", func(e *colly.HTMLElement) { - item := entity.Item{} - item["title"] = e.ChildText("h2.h4 > a") - item["url"] = e.ChildAttr("h2.h4 > a", "href") - fmt.Println(item) - if err := crawlab.SaveItem(item); err != nil { - log.Errorf("save item error: " + err.Error()) - debug.PrintStack() - return - } - }) - - c.OnRequest(func(r *colly.Request) { - fmt.Println(fmt.Sprintf("Visiting %s", r.URL.String())) - }) - - if err := c.Visit(startUrl); err != nil { - log.Errorf("visit error: " + err.Error()) - debug.PrintStack() - panic(fmt.Sprintf("Unable to visit %s", startUrl)) - } - - c.Wait() -} diff --git a/backend/template/spiders/sinastock/Spiderfile b/backend/template/spiders/sinastock/Spiderfile deleted file mode 100644 index b110cb48..00000000 --- a/backend/template/spiders/sinastock/Spiderfile +++ /dev/null @@ -1,5 +0,0 @@ -name: "sinastock" -display_name: "新浪股票 (Scrapy)" -type: "customized" -col: "results_sinastock" -cmd: "scrapy crawl sinastock_spider" \ No newline at end of file diff --git a/backend/template/spiders/sinastock/scrapy.cfg b/backend/template/spiders/sinastock/scrapy.cfg deleted file mode 100644 index 4969ad96..00000000 --- a/backend/template/spiders/sinastock/scrapy.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Automatically created by: scrapy startproject -# -# For more information about the [deploy] section see: -# https://scrapyd.readthedocs.io/en/latest/deploy.html - -[settings] -default = sinastock.settings - -[deploy] -#url = http://localhost:6800/ -project = sinastock diff --git a/backend/template/spiders/sinastock/sinastock/__init__.py b/backend/template/spiders/sinastock/sinastock/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/template/spiders/sinastock/sinastock/items.py b/backend/template/spiders/sinastock/sinastock/items.py deleted file mode 100644 index 6e3e5d8e..00000000 --- a/backend/template/spiders/sinastock/sinastock/items.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your scraped items -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/items.html - -import scrapy - - -class NewsItem(scrapy.Item): - # define the fields for your item here like: - _id = scrapy.Field() - title = scrapy.Field() - ts_str = scrapy.Field() - ts = scrapy.Field() - url = scrapy.Field() - text = scrapy.Field() - task_id = scrapy.Field() - source = scrapy.Field() - stocks = scrapy.Field() diff --git a/backend/template/spiders/sinastock/sinastock/middlewares.py b/backend/template/spiders/sinastock/sinastock/middlewares.py deleted file mode 100644 index 912b5e57..00000000 --- a/backend/template/spiders/sinastock/sinastock/middlewares.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your spider middleware -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -from scrapy import signals - - -class SinastockSpiderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the spider middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_spider_input(self, response, spider): - # Called for each response that goes through the spider - # middleware and into the spider. - - # Should return None or raise an exception. - return None - - def process_spider_output(self, response, result, spider): - # Called with the results returned from the Spider, after - # it has processed the response. - - # Must return an iterable of Request, dict or Item objects. - for i in result: - yield i - - def process_spider_exception(self, response, exception, spider): - # Called when a spider or process_spider_input() method - # (from other spider middleware) raises an exception. - - # Should return either None or an iterable of Response, dict - # or Item objects. - pass - - def process_start_requests(self, start_requests, spider): - # Called with the start requests of the spider, and works - # similarly to the process_spider_output() method, except - # that it doesn’t have a response associated. - - # Must return only requests (not items). - for r in start_requests: - yield r - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) - - -class SinastockDownloaderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the downloader middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_request(self, request, spider): - # Called for each request that goes through the downloader - # middleware. - - # Must either: - # - return None: continue processing this request - # - or return a Response object - # - or return a Request object - # - or raise IgnoreRequest: process_exception() methods of - # installed downloader middleware will be called - return None - - def process_response(self, request, response, spider): - # Called with the response returned from the downloader. - - # Must either; - # - return a Response object - # - return a Request object - # - or raise IgnoreRequest - return response - - def process_exception(self, request, exception, spider): - # Called when a download handler or a process_request() - # (from other downloader middleware) raises an exception. - - # Must either: - # - return None: continue processing this exception - # - return a Response object: stops process_exception() chain - # - return a Request object: stops process_exception() chain - pass - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) diff --git a/backend/template/spiders/sinastock/sinastock/pipelines.py b/backend/template/spiders/sinastock/sinastock/pipelines.py deleted file mode 100644 index 5a7d7cbf..00000000 --- a/backend/template/spiders/sinastock/sinastock/pipelines.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define your item pipelines here -# -# Don't forget to add your pipeline to the ITEM_PIPELINES setting -# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html diff --git a/backend/template/spiders/sinastock/sinastock/settings.py b/backend/template/spiders/sinastock/sinastock/settings.py deleted file mode 100644 index 3e01d3ca..00000000 --- a/backend/template/spiders/sinastock/sinastock/settings.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- - -# Scrapy settings for sinastock project -# -# For simplicity, this file contains only settings considered important or -# commonly used. You can find more settings consulting the documentation: -# -# https://doc.scrapy.org/en/latest/topics/settings.html -# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -BOT_NAME = 'sinastock' - -SPIDER_MODULES = ['sinastock.spiders'] -NEWSPIDER_MODULE = 'sinastock.spiders' - -# Crawl responsibly by identifying yourself (and your website) on the user-agent -# USER_AGENT = 'sinastock (+http://www.yourdomain.com)' - -# Obey robots.txt rules -ROBOTSTXT_OBEY = True - -# Configure maximum concurrent requests performed by Scrapy (default: 16) -# CONCURRENT_REQUESTS = 32 - -# Configure a delay for requests for the same website (default: 0) -# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay -# See also autothrottle settings and docs -# DOWNLOAD_DELAY = 3 -# The download delay setting will honor only one of: -# CONCURRENT_REQUESTS_PER_DOMAIN = 16 -# CONCURRENT_REQUESTS_PER_IP = 16 - -# Disable cookies (enabled by default) -# COOKIES_ENABLED = False - -# Disable Telnet Console (enabled by default) -# TELNETCONSOLE_ENABLED = False - -# Override the default request headers: -# DEFAULT_REQUEST_HEADERS = { -# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', -# 'Accept-Language': 'en', -# } - -# Enable or disable spider middlewares -# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html -# SPIDER_MIDDLEWARES = { -# 'sinastock.middlewares.SinastockSpiderMiddleware': 543, -# } - -# Enable or disable downloader middlewares -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -# DOWNLOADER_MIDDLEWARES = { -# 'sinastock.middlewares.SinastockDownloaderMiddleware': 543, -# } - -# Enable or disable extensions -# See https://doc.scrapy.org/en/latest/topics/extensions.html -# EXTENSIONS = { -# 'scrapy.extensions.telnet.TelnetConsole': None, -# } - -# Configure item pipelines -# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html -ITEM_PIPELINES = { - 'crawlab.pipelines.CrawlabMongoPipeline': 300, -} - -# Enable and configure the AutoThrottle extension (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/autothrottle.html -# AUTOTHROTTLE_ENABLED = True -# The initial download delay -# AUTOTHROTTLE_START_DELAY = 5 -# The maximum download delay to be set in case of high latencies -# AUTOTHROTTLE_MAX_DELAY = 60 -# The average number of requests Scrapy should be sending in parallel to -# each remote server -# AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 -# Enable showing throttling stats for every response received: -# AUTOTHROTTLE_DEBUG = False - -# Enable and configure HTTP caching (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings -# HTTPCACHE_ENABLED = True -# HTTPCACHE_EXPIRATION_SECS = 0 -# HTTPCACHE_DIR = 'httpcache' -# HTTPCACHE_IGNORE_HTTP_CODES = [] -# HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' diff --git a/backend/template/spiders/sinastock/sinastock/spiders/__init__.py b/backend/template/spiders/sinastock/sinastock/spiders/__init__.py deleted file mode 100644 index ebd689ac..00000000 --- a/backend/template/spiders/sinastock/sinastock/spiders/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# This package will contain the spiders of your Scrapy project -# -# Please refer to the documentation for information on how to create and manage -# your spiders. diff --git a/backend/template/spiders/sinastock/sinastock/spiders/sinastock_spider.py b/backend/template/spiders/sinastock/sinastock/spiders/sinastock_spider.py deleted file mode 100644 index 95bed149..00000000 --- a/backend/template/spiders/sinastock/sinastock/spiders/sinastock_spider.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -import os -import re -from datetime import datetime - -import scrapy -from pymongo import MongoClient - -from sinastock.items import NewsItem - -class SinastockSpiderSpider(scrapy.Spider): - name = 'sinastock_spider' - allowed_domains = ['finance.sina.com.cn'] - - def start_requests(self): - col = self.db['stocks'] - for s in col.find({}): - code, ex = s['ts_code'].split('.') - for i in range(10): - url = f'http://vip.stock.finance.sina.com.cn/corp/view/vCB_AllNewsStock.php?symbol={ex.lower()}{code}&Page={i + 1}' - yield scrapy.Request( - url=url, - callback=self.parse, - meta={'ts_code': s['ts_code']} - ) - - def parse(self, response): - for a in response.css('.datelist > ul > a'): - url = a.css('a::attr("href")').extract_first() - item = NewsItem( - title=a.css('a::text').extract_first(), - url=url, - source='sina', - stocks=[response.meta['ts_code']] - ) - yield scrapy.Request( - url=url, - callback=self.parse_detail, - meta={'item': item} - ) - - def parse_detail(self, response): - item = response.meta['item'] - text = response.css('#artibody').extract_first() - pre = re.compile('>(.*?)<') - text = ''.join(pre.findall(text)) - item['text'] = text.replace('\u3000', '') - item['ts_str'] = response.css('.date::text').extract_first() - if item['text'] is None or item['ts_str'] is None: - pass - else: - item['ts'] = datetime.strptime(item['ts_str'], '%Y年%m月%d日 %H:%M') - yield item diff --git a/backend/template/spiders/sites_inspector/sites_inspector.py b/backend/template/spiders/sites_inspector/sites_inspector.py deleted file mode 100644 index b6e264c7..00000000 --- a/backend/template/spiders/sites_inspector/sites_inspector.py +++ /dev/null @@ -1,77 +0,0 @@ -import asyncio -import os -from datetime import datetime - -import aiohttp -import requests - -from pymongo import MongoClient - -# MONGO_HOST = os.environ['MONGO_HOST'] -# MONGO_PORT = int(os.environ['MONGO_PORT']) -# MONGO_DB = os.environ['MONGO_DB'] -MONGO_HOST = 'localhost' -MONGO_PORT = 27017 -MONGO_DB = 'crawlab_test' - -mongo = MongoClient(host=MONGO_HOST, port=MONGO_PORT) -db = mongo[MONGO_DB] -col = db['sites'] - - -async def process_response(resp, **kwargs): - url = kwargs.get('url') - status = resp.status # 读取状态 - if status == 200 and ('robots.txt' in str(resp.url)): - col.update({'_id': url}, {'$set': {'has_robots': True}}) - else: - # 错误状态 - col.update({'_id': url}, {'$set': {'has_robots': False}}) - - -async def process_home_page_response(resp, **kwargs): - url = kwargs.get('url') - duration = kwargs.get('duration') - status = resp.status # 读取状态 - col.update({'_id': url}, {'$set': {'home_http_status': status, 'home_response_time': duration}}) - - -async def request_site(url: str, semaphore): - _url = 'http://' + url + '/robots.txt' - # print('crawling ' + _url) - async with semaphore: - async with aiohttp.ClientSession() as session: # <1> 开启一个会话 - async with session.get(_url) as resp: # 发送请求 - await process_response(resp=resp, url=url) - print('crawled ' + _url) - # resp = requests.get(_url) - return resp - - -async def request_site_home_page(url: str, semophore): - _url = 'http://' + url - # print('crawling ' + _url) - async with semophore: - tic = datetime.now() - async with aiohttp.ClientSession() as session: # <1> 开启一个会话 - async with session.get(_url) as resp: # 发送请求 - toc = datetime.now() - duration = (toc - tic).total_seconds() - await process_home_page_response(resp=resp, url=url, duration=duration) - print('crawled ' + _url) - - -async def run(): - semaphore = asyncio.Semaphore(50) # 限制并发量为50 - # sites = [site for site in col.find({'rank': {'$lte': 5000}})] - sites = [site for site in col.find({'rank': {'$lte': 100}})] - urls = [site['_id'] for site in sites] - to_get = [request_site(url, semaphore) for url in urls] - to_get += [request_site_home_page(url, semaphore) for url in urls] - await asyncio.wait(to_get) - - -if __name__ == '__main__': - loop = asyncio.get_event_loop() - loop.run_until_complete(run()) - loop.close() diff --git a/backend/template/spiders/v2ex_config/Spiderfile b/backend/template/spiders/v2ex_config/Spiderfile deleted file mode 100644 index bb18d40a..00000000 --- a/backend/template/spiders/v2ex_config/Spiderfile +++ /dev/null @@ -1,54 +0,0 @@ -name: "v2ex_config" -display_name: "V2ex(可配置)" -remark: "V2ex,列表+详情" -type: "configurable" -col: "results_v2ex_config" -engine: scrapy -start_url: https://v2ex.com/ -start_stage: list -stages: -- name: list - is_list: true - list_css: .cell.item - list_xpath: "" - page_css: "" - page_xpath: "" - page_attr: href - fields: - - name: title - css: a.topic-link - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: url - css: a.topic-link - xpath: "" - attr: href - next_stage: detail - remark: "" - - name: replies - css: .count_livid - xpath: "" - attr: "" - next_stage: "" - remark: "" -- name: detail - is_list: false - list_css: "" - list_xpath: "" - page_css: "" - page_xpath: "" - page_attr: "" - fields: - - name: content - css: "" - xpath: .//*[@class="markdown_body"] - attr: "" - next_stage: "" - remark: "" -settings: - AUTOTHROTTLE_ENABLED: "true" - ROBOTSTXT_OBEY: "false" - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, - like Gecko) Chrome/79.0.3945.117 Safari/537.36 diff --git a/backend/template/spiders/xueqiu/Spiderfile b/backend/template/spiders/xueqiu/Spiderfile deleted file mode 100644 index 38aa5dbe..00000000 --- a/backend/template/spiders/xueqiu/Spiderfile +++ /dev/null @@ -1,5 +0,0 @@ -name: "xueqiu" -display_name: "雪球网 (Scrapy)" -type: "customized" -col: "results_xueqiu" -cmd: "scrapy crawl xueqiu_spider" \ No newline at end of file diff --git a/backend/template/spiders/xueqiu/scrapy.cfg b/backend/template/spiders/xueqiu/scrapy.cfg deleted file mode 100644 index 2c5ce3b3..00000000 --- a/backend/template/spiders/xueqiu/scrapy.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Automatically created by: scrapy startproject -# -# For more information about the [deploy] section see: -# https://scrapyd.readthedocs.io/en/latest/deploy.html - -[settings] -default = xueqiu.settings - -[deploy] -#url = http://localhost:6800/ -project = xueqiu diff --git a/backend/template/spiders/xueqiu/xueqiu/__init__.py b/backend/template/spiders/xueqiu/xueqiu/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/template/spiders/xueqiu/xueqiu/items.py b/backend/template/spiders/xueqiu/xueqiu/items.py deleted file mode 100644 index 5471594d..00000000 --- a/backend/template/spiders/xueqiu/xueqiu/items.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your scraped items -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/items.html - -import scrapy - - -class XueqiuItem(scrapy.Item): - # define the fields for your item here like: - _id = scrapy.Field() - task_id = scrapy.Field() - id = scrapy.Field() - text = scrapy.Field() - url = scrapy.Field() - target = scrapy.Field() - view_count = scrapy.Field() - mark = scrapy.Field() - created_at = scrapy.Field() - ts = scrapy.Field() - source = scrapy.Field() diff --git a/backend/template/spiders/xueqiu/xueqiu/middlewares.py b/backend/template/spiders/xueqiu/xueqiu/middlewares.py deleted file mode 100644 index f60102ce..00000000 --- a/backend/template/spiders/xueqiu/xueqiu/middlewares.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your spider middleware -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -from scrapy import signals - - -class XueqiuSpiderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the spider middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_spider_input(self, response, spider): - # Called for each response that goes through the spider - # middleware and into the spider. - - # Should return None or raise an exception. - return None - - def process_spider_output(self, response, result, spider): - # Called with the results returned from the Spider, after - # it has processed the response. - - # Must return an iterable of Request, dict or Item objects. - for i in result: - yield i - - def process_spider_exception(self, response, exception, spider): - # Called when a spider or process_spider_input() method - # (from other spider middleware) raises an exception. - - # Should return either None or an iterable of Response, dict - # or Item objects. - pass - - def process_start_requests(self, start_requests, spider): - # Called with the start requests of the spider, and works - # similarly to the process_spider_output() method, except - # that it doesn’t have a response associated. - - # Must return only requests (not items). - for r in start_requests: - yield r - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) - - -class XueqiuDownloaderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the downloader middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_request(self, request, spider): - # Called for each request that goes through the downloader - # middleware. - - # Must either: - # - return None: continue processing this request - # - or return a Response object - # - or return a Request object - # - or raise IgnoreRequest: process_exception() methods of - # installed downloader middleware will be called - return None - - def process_response(self, request, response, spider): - # Called with the response returned from the downloader. - - # Must either; - # - return a Response object - # - return a Request object - # - or raise IgnoreRequest - return response - - def process_exception(self, request, exception, spider): - # Called when a download handler or a process_request() - # (from other downloader middleware) raises an exception. - - # Must either: - # - return None: continue processing this exception - # - return a Response object: stops process_exception() chain - # - return a Request object: stops process_exception() chain - pass - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) diff --git a/backend/template/spiders/xueqiu/xueqiu/pipelines.py b/backend/template/spiders/xueqiu/xueqiu/pipelines.py deleted file mode 100644 index 5a7d7cbf..00000000 --- a/backend/template/spiders/xueqiu/xueqiu/pipelines.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define your item pipelines here -# -# Don't forget to add your pipeline to the ITEM_PIPELINES setting -# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html diff --git a/backend/template/spiders/xueqiu/xueqiu/settings.py b/backend/template/spiders/xueqiu/xueqiu/settings.py deleted file mode 100644 index 1d898e2f..00000000 --- a/backend/template/spiders/xueqiu/xueqiu/settings.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- - -# Scrapy settings for xueqiu project -# -# For simplicity, this file contains only settings considered important or -# commonly used. You can find more settings consulting the documentation: -# -# https://doc.scrapy.org/en/latest/topics/settings.html -# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -BOT_NAME = 'xueqiu' - -SPIDER_MODULES = ['xueqiu.spiders'] -NEWSPIDER_MODULE = 'xueqiu.spiders' - -# Crawl responsibly by identifying yourself (and your website) on the user-agent -USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36' - -# Obey robots.txt rules -ROBOTSTXT_OBEY = False - -# Configure maximum concurrent requests performed by Scrapy (default: 16) -# CONCURRENT_REQUESTS = 32 - -# Configure a delay for requests for the same website (default: 0) -# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay -# See also autothrottle settings and docs -# DOWNLOAD_DELAY = 3 -# The download delay setting will honor only one of: -# CONCURRENT_REQUESTS_PER_DOMAIN = 16 -# CONCURRENT_REQUESTS_PER_IP = 16 - -# Disable cookies (enabled by default) -# COOKIES_ENABLED = False - -# Disable Telnet Console (enabled by default) -# TELNETCONSOLE_ENABLED = False - -# Override the default request headers: -# DEFAULT_REQUEST_HEADERS = { -# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', -# 'Accept-Language': 'en', -# } - -# Enable or disable spider middlewares -# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html -# SPIDER_MIDDLEWARES = { -# 'xueqiu.middlewares.XueqiuSpiderMiddleware': 543, -# } - -# Enable or disable downloader middlewares -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -# DOWNLOADER_MIDDLEWARES = { -# 'xueqiu.middlewares.XueqiuDownloaderMiddleware': 543, -# } - -# Enable or disable extensions -# See https://doc.scrapy.org/en/latest/topics/extensions.html -# EXTENSIONS = { -# 'scrapy.extensions.telnet.TelnetConsole': None, -# } - -# Configure item pipelines -# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html -ITEM_PIPELINES = { - 'crawlab.pipelines.CrawlabMongoPipeline': 300, -} - -# Enable and configure the AutoThrottle extension (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/autothrottle.html -# AUTOTHROTTLE_ENABLED = True -# The initial download delay -# AUTOTHROTTLE_START_DELAY = 5 -# The maximum download delay to be set in case of high latencies -# AUTOTHROTTLE_MAX_DELAY = 60 -# The average number of requests Scrapy should be sending in parallel to -# each remote server -# AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 -# Enable showing throttling stats for every response received: -# AUTOTHROTTLE_DEBUG = False - -# Enable and configure HTTP caching (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings -# HTTPCACHE_ENABLED = True -# HTTPCACHE_EXPIRATION_SECS = 0 -# HTTPCACHE_DIR = 'httpcache' -# HTTPCACHE_IGNORE_HTTP_CODES = [] -# HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' diff --git a/backend/template/spiders/xueqiu/xueqiu/spiders/__init__.py b/backend/template/spiders/xueqiu/xueqiu/spiders/__init__.py deleted file mode 100644 index ebd689ac..00000000 --- a/backend/template/spiders/xueqiu/xueqiu/spiders/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# This package will contain the spiders of your Scrapy project -# -# Please refer to the documentation for information on how to create and manage -# your spiders. diff --git a/backend/template/spiders/xueqiu/xueqiu/spiders/xueqiu_spider.py b/backend/template/spiders/xueqiu/xueqiu/spiders/xueqiu_spider.py deleted file mode 100644 index a746e156..00000000 --- a/backend/template/spiders/xueqiu/xueqiu/spiders/xueqiu_spider.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -import json -from datetime import datetime -from time import sleep - -import scrapy - -from xueqiu.items import XueqiuItem - - -class XueqiuSpiderSpider(scrapy.Spider): - name = 'xueqiu_spider' - allowed_domains = ['xueqiu.com'] - - def start_requests(self): - return [scrapy.Request( - url='https://xueqiu.com', - callback=self.parse_home - )] - - def parse_home(self, response): - yield scrapy.Request( - url='https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=-1&count=20&category=6' - ) - - def parse(self, response): - data = json.loads(response.body) - next_max_id = data.get('next_max_id') - sleep(1) - for row in data.get('list'): - d = json.loads(row.get('data')) - item = XueqiuItem( - id=d['id'], - text=d['text'], - mark=d['mark'], - url=d['target'], - created_at=d['created_at'], - ts=datetime.fromtimestamp(d['created_at'] / 1e3), - view_count=d['view_count'], - source='xueqiu' - ) - yield item - - yield scrapy.Request( - url=f'https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id={next_max_id}&count=20&category=6' - ) diff --git a/backend/template/spiders/xueqiu_config/Spiderfile b/backend/template/spiders/xueqiu_config/Spiderfile deleted file mode 100644 index 0de50e9e..00000000 --- a/backend/template/spiders/xueqiu_config/Spiderfile +++ /dev/null @@ -1,39 +0,0 @@ -name: "xueqiu_config" -display_name: "雪球网(可配置)" -remark: "雪球网新闻,列表" -type: "configurable" -col: "results_xueqiu_config" -engine: scrapy -start_url: https://xueqiu.com/ -start_stage: list -stages: -- name: list - is_list: true - list_css: "" - list_xpath: .//*[contains(@class, "AnonymousHome_home__timeline__item")] - page_css: "" - page_xpath: "" - page_attr: "" - fields: - - name: title - css: h3 > a - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: url - css: h3 > a - xpath: "" - attr: href - next_stage: "" - remark: "" - - name: abstract - css: p - xpath: "" - attr: "" - next_stage: "" - remark: "" -settings: - ROBOTSTXT_OBEY: "false" - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, - like Gecko) Chrome/78.0.3904.108 Safari/537.36 diff --git a/backend/template/spiders/zongheng_config/Spiderfile b/backend/template/spiders/zongheng_config/Spiderfile deleted file mode 100644 index 0163fac7..00000000 --- a/backend/template/spiders/zongheng_config/Spiderfile +++ /dev/null @@ -1,45 +0,0 @@ -name: "zongheng_config" -display_name: "纵横(可配置)" -remark: "纵横小说网,列表" -type: "configurable" -col: "results_zongheng_config" -engine: scrapy -start_url: http://www.zongheng.com/rank/details.html?rt=1&d=1 -start_stage: list -stages: -- name: list - is_list: true - list_css: .rank_d_list - list_xpath: "" - page_css: "" - page_xpath: "" - page_attr: href - fields: - - name: title - css: .rank_d_b_name > a - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: url - css: .rank_d_b_name > a - xpath: "" - attr: href - next_stage: "" - remark: "" - - name: abstract - css: body - xpath: "" - attr: "" - next_stage: "" - remark: "" - - name: votes - css: .rank_d_b_ticket - xpath: "" - attr: "" - next_stage: "" - remark: "" -settings: - ROBOTSTXT_OBEY: "false" - USER_AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, - like Gecko) Chrome/78.0.3904.108 Safari/537.36 diff --git a/backend/test/test.http b/backend/test/test.http deleted file mode 100644 index bde72001..00000000 --- a/backend/test/test.http +++ /dev/null @@ -1,49 +0,0 @@ -# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection). -# -# Following HTTP Request Live Templates are available: -# * 'gtrp' and 'gtr' create a GET request with or without query parameters; -# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body; -# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data); -PUT http://localhost:8000/schedules -Content-Type: application/json -#Content-Type: application/x-www-form-urlencoded - -{ - "cron": "*/10 * * * * *", - "spider_id": "5d2ead494bdee04810bb7654" -} - -### cron=*/10 * * * * *&spider_id=5d2ead494bdee04810bb7654 - -DELETE http://localhost:8000/schedules/5d31b5334bdee082f6e69e7a - -### - -DELETE http://localhost:8000/spiders/5d31a6ed4bdee07b25d70c7b - -### - - -### - -PUT http://localhost:8000/tasks -Content-Type: application/json - -{ - "spider_id": "5d32f20f4bdee0f4aae526de", - "node_id": "5d3343cc4bdee01cb772883e" -} - -### - -POST http://localhost:8000/spiders/5d32ad224bdee0a60ee5639c/publish - -### - -POST http://localhost:8000/spiders - -### - -GET http://localhost:8000/tasks/bb79ec82-1e8f-41c4-858a-5cb682396409/log - -### diff --git a/backend/utils/array.go b/backend/utils/array.go deleted file mode 100644 index 889430ed..00000000 --- a/backend/utils/array.go +++ /dev/null @@ -1,10 +0,0 @@ -package utils - -func StringArrayContains(arr []string, str string) bool { - for _, s := range arr { - if s == str { - return true - } - } - return false -} diff --git a/backend/utils/chan.go b/backend/utils/chan.go deleted file mode 100644 index c0144340..00000000 --- a/backend/utils/chan.go +++ /dev/null @@ -1,40 +0,0 @@ -package utils - -import ( - "sync" -) - -var TaskExecChanMap = NewChanMap() - -type ChanMap struct { - m sync.Map -} - -func NewChanMap() *ChanMap { - return &ChanMap{m: sync.Map{}} -} - -func (cm *ChanMap) Chan(key string) chan string { - if ch, ok := cm.m.Load(key); ok { - return ch.(interface{}).(chan string) - } - ch := make(chan string, 10) - cm.m.Store(key, ch) - return ch -} - -func (cm *ChanMap) ChanBlocked(key string) chan string { - if ch, ok := cm.m.Load(key); ok { - return ch.(interface{}).(chan string) - } - ch := make(chan string) - cm.m.Store(key, ch) - return ch -} - -func (cm *ChanMap) HasChanKey(key string) bool { - if _, ok := cm.m.Load(key); ok { - return true - } - return false -} diff --git a/backend/utils/chan_test.go b/backend/utils/chan_test.go deleted file mode 100644 index 4bc75917..00000000 --- a/backend/utils/chan_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package utils - -import ( - . "github.com/smartystreets/goconvey/convey" - "sync" - "testing" -) - -func TestNewChanMap(t *testing.T) { - mapTest := sync.Map{} - chanTest := make(chan string) - test := "test" - - Convey("Call NewChanMap to generate ChanMap", t, func() { - mapTest.Store("test", chanTest) - chanMapTest := ChanMap{mapTest} - chanMap := NewChanMap() - chanMap.m.Store("test", chanTest) - - Convey(test, func() { - v1, ok := chanMap.m.Load("test") - So(ok, ShouldBeTrue) - v2, ok := chanMapTest.m.Load("test") - So(ok, ShouldBeTrue) - So(v1, ShouldResemble, v2) - }) - }) -} - -func TestChan(t *testing.T) { - mapTest := sync.Map{} - chanTest := make(chan string) - mapTest.Store("test", chanTest) - chanMapTest := ChanMap{mapTest} - - Convey("Test Chan use exist key", t, func() { - ch1 := chanMapTest.Chan("test") - Convey("ch1 should equal chanTest", func() { - So(ch1, ShouldEqual, chanTest) - }) - }) - Convey("Test Chan use no-exist key", t, func() { - ch2 := chanMapTest.Chan("test2") - Convey("ch2 should equal chanMapTest.m[test2]", func() { - v, ok := chanMapTest.m.Load("test2") - So(ok, ShouldBeTrue) - So(v, ShouldEqual, ch2) - }) - Convey("Cap of chanMapTest.m[test2] should equal 10", func() { - So(10, ShouldEqual, cap(ch2)) - }) - }) -} - -func TestChanBlocked(t *testing.T) { - mapTest := sync.Map{} - chanTest := make(chan string) - mapTest.Store("test", chanTest) - chanMapTest := ChanMap{mapTest} - - Convey("Test Chan use exist key", t, func() { - ch1 := chanMapTest.ChanBlocked("test") - Convey("ch1 should equal chanTest", func() { - So(ch1, ShouldEqual, chanTest) - }) - }) - Convey("Test Chan use no-exist key", t, func() { - ch2 := chanMapTest.ChanBlocked("test2") - Convey("ch2 should equal chanMapTest.m[test2]", func() { - v, ok := chanMapTest.m.Load("test2") - So(ok, ShouldBeTrue) - So(v, ShouldEqual, ch2) - }) - Convey("Cap of chanMapTest.m[test2] should equal 10", func() { - So(0, ShouldEqual, cap(ch2)) - }) - }) -} diff --git a/backend/utils/encrypt.go b/backend/utils/encrypt.go deleted file mode 100644 index 52013b9c..00000000 --- a/backend/utils/encrypt.go +++ /dev/null @@ -1,16 +0,0 @@ -package utils - -import ( - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "encoding/hex" -) - -func ComputeHmacSha256(message string, secret string) string { - key := []byte(secret) - h := hmac.New(sha256.New, key) - h.Write([]byte(message)) - sha := hex.EncodeToString(h.Sum(nil)) - return base64.StdEncoding.EncodeToString([]byte(sha)) -} diff --git a/backend/utils/file.go b/backend/utils/file.go deleted file mode 100644 index 040b78de..00000000 --- a/backend/utils/file.go +++ /dev/null @@ -1,385 +0,0 @@ -package utils - -import ( - "archive/zip" - "bufio" - "fmt" - "github.com/apex/log" - "io" - "io/ioutil" - "os" - "path" - "path/filepath" - "runtime/debug" - "strings" -) - -// 删除文件 -func RemoveFiles(path string) { - if err := os.RemoveAll(path); err != nil { - log.Errorf("remove files error: %s, path: %s", err.Error(), path) - debug.PrintStack() - } -} - -// 读取文件一行 -func ReadFileOneLine(fileName string) string { - file := OpenFile(fileName) - defer Close(file) - buf := bufio.NewReader(file) - line, err := buf.ReadString('\n') - if err != nil { - log.Errorf("read file error: %s", err.Error()) - return "" - } - return line -} - -func GetSpiderMd5Str(file string) string { - md5Str := ReadFileOneLine(file) - // 去掉空格以及换行符 - md5Str = strings.Replace(md5Str, " ", "", -1) - md5Str = strings.Replace(md5Str, "\n", "", -1) - return md5Str -} - -// 创建文件 -func OpenFile(fileName string) *os.File { - file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR, os.ModePerm) - if err != nil { - log.Errorf("create file error: %s, file_name: %s", err.Error(), fileName) - debug.PrintStack() - return nil - } - return file -} - -// 创建文件夹 -func CreateDirPath(filePath string) { - if !Exists(filePath) { - if err := os.MkdirAll(filePath, os.ModePerm); err != nil { - log.Errorf("create file error: %s, file_path: %s", err.Error(), filePath) - debug.PrintStack() - } - } -} - -// 判断所给路径文件/文件夹是否存在 -func Exists(path string) bool { - _, err := os.Stat(path) //os.Stat获取文件信息 - if err != nil { - return os.IsExist(err) - } - return true -} - -// 判断所给路径是否为文件夹 -func IsDir(path string) bool { - s, err := os.Stat(path) - if err != nil { - return false - } - return s.IsDir() -} - -func ListDir(path string) []os.FileInfo { - list, err := ioutil.ReadDir(path) - if err != nil { - log.Errorf(err.Error()) - debug.PrintStack() - return nil - } - return list -} - -// 判断所给路径是否为文件 -func IsFile(path string) bool { - return !IsDir(path) -} - -/** -@tarFile:压缩文件路径 -@dest:解压文件夹 -*/ -func DeCompressByPath(tarFile, dest string) error { - srcFile, err := os.Open(tarFile) - if err != nil { - return err - } - defer Close(srcFile) - return DeCompress(srcFile, dest) -} - -/** -@zipFile:压缩文件 -@dstPath:解压之后文件保存路径 -*/ -func DeCompress(srcFile *os.File, dstPath string) error { - // 如果保存路径不存在,创建一个 - if !Exists(dstPath) { - if err := os.MkdirAll(dstPath, os.ModePerm); err != nil { - debug.PrintStack() - return err - } - } - - // 读取zip文件 - zipFile, err := zip.OpenReader(srcFile.Name()) - if err != nil { - log.Errorf("Unzip File Error:" + err.Error()) - debug.PrintStack() - return err - } - defer Close(zipFile) - - // 遍历zip内所有文件和目录 - for _, innerFile := range zipFile.File { - // 获取该文件数据 - info := innerFile.FileInfo() - - // 如果是目录,则创建一个 - if info.IsDir() { - err = os.MkdirAll(filepath.Join(dstPath, innerFile.Name), os.ModeDir|os.ModePerm) - if err != nil { - log.Errorf("Unzip File Error : " + err.Error()) - debug.PrintStack() - return err - } - continue - } - - // 如果文件目录不存在,则创建一个 - dirPath := filepath.Join(dstPath, filepath.Dir(innerFile.Name)) - if !Exists(dirPath) { - if err = os.MkdirAll(dirPath, os.ModeDir|os.ModePerm); err != nil { - log.Errorf("Unzip File Error : " + err.Error()) - debug.PrintStack() - return err - } - } - - // 打开该文件 - srcFile, err := innerFile.Open() - if err != nil { - log.Errorf("Unzip File Error : " + err.Error()) - debug.PrintStack() - continue - } - - // 创建新文件 - newFilePath := filepath.Join(dstPath, innerFile.Name) - newFile, err := os.OpenFile(newFilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, info.Mode()) - if err != nil { - log.Errorf("Unzip File Error : " + err.Error()) - debug.PrintStack() - continue - } - - // 拷贝该文件到新文件中 - if _, err := io.Copy(newFile, srcFile); err != nil { - debug.PrintStack() - return err - } - - // 关闭该文件 - if err := srcFile.Close(); err != nil { - debug.PrintStack() - return err - } - - // 关闭新文件 - if err := newFile.Close(); err != nil { - debug.PrintStack() - return err - } - } - return nil -} - -//压缩文件 -//files 文件数组,可以是不同dir下的文件或者文件夹 -//dest 压缩文件存放地址 -func Compress(files []*os.File, dest string) error { - d, _ := os.Create(dest) - defer Close(d) - w := zip.NewWriter(d) - defer Close(w) - for _, file := range files { - if err := _Compress(file, "", w); err != nil { - return err - } - } - return nil -} - -func _Compress(file *os.File, prefix string, zw *zip.Writer) error { - info, err := file.Stat() - if err != nil { - debug.PrintStack() - return err - } - if info.IsDir() { - prefix = prefix + "/" + info.Name() - fileInfos, err := file.Readdir(-1) - if err != nil { - debug.PrintStack() - return err - } - for _, fi := range fileInfos { - f, err := os.Open(file.Name() + "/" + fi.Name()) - if err != nil { - debug.PrintStack() - return err - } - err = _Compress(f, prefix, zw) - if err != nil { - debug.PrintStack() - return err - } - } - } else { - header, err := zip.FileInfoHeader(info) - if err != nil { - debug.PrintStack() - return err - } - header.Name = prefix + "/" + header.Name - writer, err := zw.CreateHeader(header) - if err != nil { - debug.PrintStack() - return err - } - _, err = io.Copy(writer, file) - Close(file) - if err != nil { - debug.PrintStack() - return err - } - } - return nil -} - -func GetFilesFromDir(dirPath string) ([]*os.File, error) { - var res []*os.File - for _, fInfo := range ListDir(dirPath) { - f, err := os.Open(filepath.Join(dirPath, fInfo.Name())) - if err != nil { - return res, err - } - res = append(res, f) - } - return res, nil -} - -func GetAllFilesFromDir(dirPath string) ([]*os.File, error) { - var res []*os.File - if err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { - if !IsDir(path) { - f, err2 := os.Open(path) - if err2 != nil { - return err - } - res = append(res, f) - } - return nil - }); err != nil { - log.Error(err.Error()) - debug.PrintStack() - return res, err - } - return res, nil -} - -// File copies a single file from src to dst -func CopyFile(src, dst string) error { - var err error - var srcFd *os.File - var dstFd *os.File - var srcInfo os.FileInfo - - if srcFd, err = os.Open(src); err != nil { - return err - } - defer srcFd.Close() - - if dstFd, err = os.Create(dst); err != nil { - return err - } - defer dstFd.Close() - - if _, err = io.Copy(dstFd, srcFd); err != nil { - return err - } - if srcInfo, err = os.Stat(src); err != nil { - return err - } - return os.Chmod(dst, srcInfo.Mode()) -} - -// Dir copies a whole directory recursively -func CopyDir(src string, dst string) error { - var err error - var fds []os.FileInfo - var srcInfo os.FileInfo - - if srcInfo, err = os.Stat(src); err != nil { - return err - } - - if err = os.MkdirAll(dst, srcInfo.Mode()); err != nil { - return err - } - - if fds, err = ioutil.ReadDir(src); err != nil { - return err - } - for _, fd := range fds { - srcfp := path.Join(src, fd.Name()) - dstfp := path.Join(dst, fd.Name()) - - if fd.IsDir() { - if err = CopyDir(srcfp, dstfp); err != nil { - fmt.Println(err) - } - } else { - if err = CopyFile(srcfp, dstfp); err != nil { - fmt.Println(err) - } - } - } - return nil -} - -// 设置文件变量值 -// 可以理解为将文件中的变量占位符替换为想要设置的值 -func SetFileVariable(filePath string, key string, value string) error { - // 占位符标识 - sep := "###" - - // 读取文件到字节 - contentBytes, err := ioutil.ReadFile(filePath) - if err != nil { - return err - } - - // 将字节转化为文本 - content := string(contentBytes) - - // 替换文本 - content = strings.Replace(content, fmt.Sprintf("%s%s%s", sep, key, sep), value, -1) - - // 打开文件 - f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC, 0777) - if err != nil { - return err - } - - // 将替换后的内容写入文件 - if _, err := f.Write([]byte(content)); err != nil { - return err - } - - f.Close() - - return nil -} diff --git a/backend/utils/file_test.go b/backend/utils/file_test.go deleted file mode 100644 index 4af32d0d..00000000 --- a/backend/utils/file_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package utils - -import ( - "archive/zip" - . "github.com/smartystreets/goconvey/convey" - "io" - "log" - "os" - "runtime/debug" - "testing" -) - -func TestExists(t *testing.T) { - var pathString = "../config" - var wrongPathString = "test" - - Convey("Test path or file is Exists or not", t, func() { - res := Exists(pathString) - Convey("The result should be true", func() { - So(res, ShouldEqual, true) - }) - wrongRes := Exists(wrongPathString) - Convey("The result should be false", func() { - So(wrongRes, ShouldEqual, false) - }) - }) -} - -func TestIsDir(t *testing.T) { - var pathString = "../config" - var fileString = "../config/config.go" - var wrongString = "test" - - Convey("Test path is folder or not", t, func() { - res := IsDir(pathString) - So(res, ShouldEqual, true) - fileRes := IsDir(fileString) - So(fileRes, ShouldEqual, false) - wrongRes := IsDir(wrongString) - So(wrongRes, ShouldEqual, false) - }) -} - -func TestCompress(t *testing.T) { - err := os.Mkdir("testCompress", os.ModePerm) - if err != nil { - t.Error("create testCompress failed") - } - var pathString = "testCompress" - var files []*os.File - var disPath = "testCompress" - file, err := os.Open(pathString) - if err != nil { - t.Error("open source path failed") - } - files = append(files, file) - Convey("Verify dispath is valid path", t, func() { - er := Compress(files, disPath) - Convey("err should be nil", func() { - So(er, ShouldEqual, nil) - }) - }) - _ = os.RemoveAll("testCompress") - -} -func Zip(zipFile string, fileList []string) error { - // 创建 zip 包文件 - fw, err := os.Create(zipFile) - if err != nil { - log.Fatal() - } - defer Close(fw) - - // 实例化新的 zip.Writer - zw := zip.NewWriter(fw) - defer Close(zw) - - for _, fileName := range fileList { - fr, err := os.Open(fileName) - if err != nil { - return err - } - fi, err := fr.Stat() - if err != nil { - return err - } - // 写入文件的头信息 - fh, err := zip.FileInfoHeader(fi) - if err != nil { - return err - } - w, err := zw.CreateHeader(fh) - if err != nil { - return err - } - // 写入文件内容 - _, err = io.Copy(w, fr) - if err != nil { - return err - } - } - return nil -} - -func TestDeCompress(t *testing.T) { - err := os.Mkdir("testDeCompress", os.ModePerm) - if err != nil { - t.Error(err) - - } - err = Zip("demo.zip", []string{}) - if err != nil { - t.Error("create zip file failed") - } - tmpFile, err := os.OpenFile("demo.zip", os.O_RDONLY, 0777) - if err != nil { - debug.PrintStack() - t.Error("open demo.zip failed") - } - var dstPath = "./testDeCompress" - Convey("Test DeCopmress func", t, func() { - - err := DeCompress(tmpFile, dstPath) - So(err, ShouldEqual, nil) - }) - _ = os.RemoveAll("testDeCompress") - _ = os.Remove("demo.zip") - -} diff --git a/backend/utils/helpers.go b/backend/utils/helpers.go deleted file mode 100644 index e181c66c..00000000 --- a/backend/utils/helpers.go +++ /dev/null @@ -1,60 +0,0 @@ -package utils - -import ( - "crawlab/entity" - "encoding/json" - "github.com/apex/log" - "github.com/gomodule/redigo/redis" - "io" - "reflect" - "runtime/debug" - "unsafe" -) - -func BytesToString(b []byte) string { - return *(*string)(unsafe.Pointer(&b)) -} - -func GetJson(message entity.NodeMessage) string { - msgBytes, err := json.Marshal(&message) - if err != nil { - log.Errorf("node message to json error: %s", err.Error()) - debug.PrintStack() - return "" - } - return BytesToString(msgBytes) -} - -func GetMessage(message redis.Message) *entity.NodeMessage { - msg := entity.NodeMessage{} - if err := json.Unmarshal(message.Data, &msg); err != nil { - log.Errorf("message byte to object error: %s", err.Error()) - debug.PrintStack() - return nil - } - return &msg -} - -func Close(c io.Closer) { - err := c.Close() - if err != nil { - //log.WithError(err).Error("关闭资源文件失败。") - } -} - -func Contains(array interface{}, val interface{}) (fla bool) { - fla = false - switch reflect.TypeOf(array).Kind() { - case reflect.Slice: - { - s := reflect.ValueOf(array) - for i := 0; i < s.Len(); i++ { - if reflect.DeepEqual(val, s.Index(i).Interface()) { - fla = true - return - } - } - } - } - return -} diff --git a/backend/utils/model.go b/backend/utils/model.go deleted file mode 100644 index 048b0001..00000000 --- a/backend/utils/model.go +++ /dev/null @@ -1,24 +0,0 @@ -package utils - -import ( - "crawlab/constants" - "encoding/json" - "github.com/globalsign/mgo/bson" - "strings" -) - -func IsObjectIdNull(id bson.ObjectId) bool { - return id.Hex() == constants.ObjectIdNull -} - -func InterfaceToString(value interface{}) string { - bytes, err := json.Marshal(value) - if err != nil { - return "" - } - str := string(bytes) - if strings.HasPrefix(str, "\"") && strings.HasSuffix(str, "\"") { - str = str[1 : len(str)-1] - } - return str -} diff --git a/backend/utils/model_test.go b/backend/utils/model_test.go deleted file mode 100644 index d641865c..00000000 --- a/backend/utils/model_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package utils - -import ( - "github.com/globalsign/mgo/bson" - . "github.com/smartystreets/goconvey/convey" - "strconv" - "testing" - "time" -) - -func TestIsObjectIdNull(t *testing.T) { - var id bson.ObjectId = "123455" - Convey("Test Object ID is null or not", t, func() { - res := IsObjectIdNull(id) - So(res, ShouldEqual, false) - }) -} - -func TestInterfaceToString(t *testing.T) { - var valueBson bson.ObjectId = "12345" - var valueString = "12345" - var valueInt = 12345 - var valueTime = time.Now().Add(60 * time.Second) - var valueOther = []string{"a", "b"} - - Convey("Test InterfaceToString", t, func() { - resBson := InterfaceToString(valueBson) - Convey("resBson should be string value", func() { - So(resBson, ShouldEqual, valueBson.Hex()) - }) - resString := InterfaceToString(valueString) - Convey("resString should be string value", func() { - So(resString, ShouldEqual, valueString) - }) - resInt := InterfaceToString(valueInt) - Convey("resInt should be string value", func() { - So(resInt, ShouldEqual, strconv.Itoa(valueInt)) - }) - resTime := InterfaceToString(valueTime) - Convey("resTime should be string value", func() { - So(resTime, ShouldEqual, valueTime.String()) - }) - resOther := InterfaceToString(valueOther) - Convey("resOther should be empty string", func() { - So(resOther, ShouldEqual, "") - }) - }) - -} diff --git a/backend/utils/rpc.go b/backend/utils/rpc.go deleted file mode 100644 index 03414199..00000000 --- a/backend/utils/rpc.go +++ /dev/null @@ -1,14 +0,0 @@ -package utils - -import "encoding/json" - -// Object 转化为 String -func ObjectToString(params interface{}) string { - bytes, _ := json.Marshal(params) - return BytesToString(bytes) -} - -// 获取 RPC 参数 -func GetRpcParam(key string, params map[string]string) string { - return params[key] -} diff --git a/backend/utils/spider.go b/backend/utils/spider.go deleted file mode 100644 index 4484ccf0..00000000 --- a/backend/utils/spider.go +++ /dev/null @@ -1,8 +0,0 @@ -package utils - -func GetSpiderCol(col string, name string) string { - if col == "" { - return "results_" + name - } - return col -} diff --git a/backend/utils/system.go b/backend/utils/system.go deleted file mode 100644 index e6d2f591..00000000 --- a/backend/utils/system.go +++ /dev/null @@ -1,149 +0,0 @@ -package utils - -import ( - "crawlab/constants" - "crawlab/entity" - "encoding/json" - "github.com/apex/log" - "github.com/spf13/viper" - "io/ioutil" - "path" - "runtime/debug" - "strings" -) - -func GetLangList() []entity.Lang { - list := []entity.Lang{ - // 语言 - { - Name: "Python", - ExecutableName: "python", - ExecutablePaths: []string{"/usr/bin/python", "/usr/local/bin/python"}, - DepExecutablePath: "/usr/local/bin/pip", - LockPath: "/tmp/install-python.lock", - DepFileName: "requirements.txt", - InstallDepArgs: "install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt", - Type: constants.LangTypeLang, - }, - { - Name: "Node.js", - ExecutableName: "node", - ExecutablePaths: []string{"/usr/bin/node", "/usr/local/bin/node"}, - DepExecutablePath: "/usr/local/bin/npm", - LockPath: "/tmp/install-nodejs.lock", - InstallScript: "install-nodejs.sh", - DepFileName: "package.json", - InstallDepArgs: "install -g --registry=https://registry.npm.taobao.org", - Type: constants.LangTypeLang, - }, - { - Name: "Java", - ExecutableName: "java", - ExecutablePaths: []string{"/usr/bin/java", "/usr/local/bin/java"}, - LockPath: "/tmp/install-java.lock", - InstallScript: "install-java.sh", - Type: constants.LangTypeLang, - }, - { - Name: ".Net Core", - ExecutableName: "dotnet", - ExecutablePaths: []string{"/usr/bin/dotnet", "/usr/local/bin/dotnet"}, - LockPath: "/tmp/install-dotnet.lock", - InstallScript: "install-dotnet.sh", - Type: constants.LangTypeLang, - }, - { - Name: "PHP", - ExecutableName: "php", - ExecutablePaths: []string{"/usr/bin/php", "/usr/local/bin/php"}, - LockPath: "/tmp/install-php.lock", - InstallScript: "install-php.sh", - Type: constants.LangTypeLang, - }, - { - Name: "Golang", - ExecutableName: "go", - ExecutablePaths: []string{"/usr/bin/go", "/usr/local/bin/go"}, - LockPath: "/tmp/install-go.lock", - InstallScript: "install-go.sh", - Type: constants.LangTypeLang, - }, - // WebDriver - { - Name: "Chrome Driver", - ExecutableName: "chromedriver", - ExecutablePaths: []string{"/usr/bin/chromedriver", "/usr/local/bin/chromedriver"}, - LockPath: "/tmp/install-chromedriver.lock", - InstallScript: "install-chromedriver.sh", - Type: constants.LangTypeWebDriver, - }, - { - Name: "Firefox", - ExecutableName: "firefox", - ExecutablePaths: []string{"/usr/bin/firefox", "/usr/local/bin/firefox"}, - LockPath: "/tmp/install-firefox.lock", - InstallScript: "install-firefox.sh", - Type: constants.LangTypeWebDriver, - }, - } - return list -} - -// 获取语言列表 -func GetLangListPlain() []entity.Lang { - list := GetLangList() - return list -} - -// 根据语言名获取语言实例,不包含状态 -func GetLangFromLangNamePlain(name string) entity.Lang { - langList := GetLangListPlain() - for _, lang := range langList { - if lang.ExecutableName == name { - return lang - } - } - return entity.Lang{} -} - -func GetPackageJsonDeps(filepath string) (deps []string, err error) { - data, err := ioutil.ReadFile(filepath) - if err != nil { - log.Errorf("get package.json deps error: " + err.Error()) - debug.PrintStack() - return deps, err - } - var packageJson entity.PackageJson - if err := json.Unmarshal(data, &packageJson); err != nil { - log.Errorf("get package.json deps error: " + err.Error()) - debug.PrintStack() - return deps, err - } - - for d, v := range packageJson.Dependencies { - deps = append(deps, d+"@"+v) - } - - return deps, nil -} - -// 获取系统脚本列表 -func GetSystemScripts() (res []string) { - scriptsPath := viper.GetString("server.scripts") - for _, fInfo := range ListDir(scriptsPath) { - if !fInfo.IsDir() && strings.HasSuffix(fInfo.Name(), ".sh") { - res = append(res, fInfo.Name()) - } - } - return res -} - -func GetSystemScriptPath(scriptName string) string { - scriptsPath := viper.GetString("server.scripts") - for _, name := range GetSystemScripts() { - if name == scriptName { - return path.Join(scriptsPath, name) - } - } - return "" -} diff --git a/backend/utils/time.go b/backend/utils/time.go deleted file mode 100644 index 84b40f4e..00000000 --- a/backend/utils/time.go +++ /dev/null @@ -1,16 +0,0 @@ -package utils - -import "time" - -func GetLocalTime(t time.Time) time.Time { - return t.In(time.Local) -} - -func GetTimeString(t time.Time) string { - return t.Format("2006-01-02 15:04:05") -} - -func GetLocalTimeString(t time.Time) string { - t = GetLocalTime(t) - return GetTimeString(t) -} diff --git a/backend/utils/user.go b/backend/utils/user.go deleted file mode 100644 index 46933f9e..00000000 --- a/backend/utils/user.go +++ /dev/null @@ -1,14 +0,0 @@ -package utils - -import ( - "crypto/md5" - "fmt" - "io" -) - -func EncryptPassword(str string) string { - w := md5.New() - _, _ = io.WriteString(w, str) - md5str := fmt.Sprintf("%x", w.Sum(nil)) - return md5str -} diff --git a/backend/utils/user_test.go b/backend/utils/user_test.go deleted file mode 100644 index 68cf4d65..00000000 --- a/backend/utils/user_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package utils - -import ( - . "github.com/smartystreets/goconvey/convey" - "testing" -) - -func TestEncryptPassword(t *testing.T) { - var passwd = "test" - Convey("Test EncryptPassword", t, func() { - res := EncryptPassword(passwd) - t.Log(res) - }) -} From 54fd15892501faead77a289902406e7ece3e74b5 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Fri, 4 Dec 2020 15:38:26 +0800 Subject: [PATCH 02/19] code cleanup --- backend/go.mod | 29 ---------------- backend/go.sum | 92 ++++---------------------------------------------- 2 files changed, 7 insertions(+), 114 deletions(-) diff --git a/backend/go.mod b/backend/go.mod index 6d2ab8d5..de7a5156 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -8,40 +8,11 @@ replace ( ) require ( - github.com/Masterminds/semver v1.4.2 // indirect - github.com/Masterminds/sprig v2.16.0+incompatible // indirect - github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd // indirect - github.com/aokoli/goutils v1.0.1 // indirect github.com/apex/log v1.9.0 - github.com/cenkalti/backoff/v4 v4.1.0 // indirect github.com/crawlab-team/crawlab-core v0.0.0-00010101000000-000000000000 github.com/crawlab-team/crawlab-db v0.0.2 - github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/gin-gonic/gin v1.6.3 - github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 // indirect github.com/go-playground/validator/v10 v10.3.0 - github.com/gomodule/redigo v2.0.0+incompatible // indirect - github.com/hashicorp/go-sockaddr v1.0.0 // indirect - github.com/huandu/xstrings v1.2.0 // indirect - github.com/imdario/mergo v0.3.6 // indirect - github.com/imroc/req v0.3.0 // indirect - github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 // indirect - github.com/matcornic/hermes v1.2.0 // indirect - github.com/mattn/go-runewidth v0.0.3 // indirect - github.com/olekukonko/tablewriter v0.0.1 // indirect github.com/olivere/elastic/v7 v7.0.15 - github.com/pkg/errors v0.9.1 // indirect - github.com/satori/go.uuid v1.2.0 // indirect - github.com/smartystreets/goconvey v1.6.4 // indirect github.com/spf13/viper v1.7.1 - github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect - go.uber.org/atomic v1.6.0 // indirect - golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f // indirect - gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect - gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect - gopkg.in/russross/blackfriday.v2 v2.0.0 // indirect - gopkg.in/src-d/go-git.v4 v4.13.1 // indirect - gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 5779ab97..a0c5fc74 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -14,37 +14,24 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= -github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/sprig v2.16.0+incompatible h1:QZbMUPxRQ50EKAq3LFMnxddMu88/EUUG3qmxwtDmPsY= github.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd h1:+CYOsXi89xOqBkj7CuEJjA2It+j+R3ngUZEydr6mtkw= github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/aokoli/goutils v1.0.1 h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg= github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= -github.com/apex/log v1.1.4 h1:3Zk+boorIQAAGBrHn0JUtAau4ihMamT4WdnfdnXM1zQ= -github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= -github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= @@ -60,8 +47,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/cenkalti/backoff/v4 v4.0.2 h1:JIufpQLbh4DkbQoii76ItQIUFzevQSqOLZca4eamEDs= -github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc= github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -72,7 +57,6 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -92,16 +76,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= -github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= -github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= -github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= @@ -112,26 +88,6 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk= -github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4= -github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi880= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= @@ -143,6 +99,7 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o= github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -223,7 +180,6 @@ github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= -github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= @@ -240,21 +196,19 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/matcornic/hermes v1.2.0 h1:AuqZpYcTOtTB7cahdevLfnhIpfzmpqw5Czv8vpdnFDU= @@ -263,15 +217,14 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -326,7 +279,6 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -353,8 +305,6 @@ github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= @@ -370,36 +320,22 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= -github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= -github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= -github.com/swaggo/swag v1.5.1 h1:2Agm8I4K5qb00620mHq0VJ05/KT4FtmALPIcQR9lEZM= -github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.6.6 h1:3YX5hmuUyCMT/OqqnjW92gULAfHg3hVjpcPm53N64RY= -github.com/swaggo/swag v1.6.6/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.5-pre h1:jyJKFOSEbdOc2HODrf2qcCkYOdq7zzXqA9bhW5oV4fM= -github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.5-pre h1:5YV9PsFAN+ndcCtTM7s60no7nY7eTG3LPtxhSwuxzCs= -github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -421,7 +357,6 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/Le golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -446,7 +381,6 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -458,13 +392,10 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -482,7 +413,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -492,8 +422,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -519,10 +447,7 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a h1:mEQZbbaBjWyLNy0tmZmgEuQAR8XOQ3hL8GYi3J/NG64= @@ -568,10 +493,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= @@ -598,6 +519,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 5e47222dfed066523cba19975a450e983654302d Mon Sep 17 00:00:00 2001 From: marvzhang Date: Thu, 18 Feb 2021 10:03:48 +0800 Subject: [PATCH 03/19] updated config.yml --- backend/conf/config.yml | 11 +++--- backend/go.mod | 7 +++- backend/go.sum | 79 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/backend/conf/config.yml b/backend/conf/config.yml index d3dc39a3..8f69d28f 100644 --- a/backend/conf/config.yml +++ b/backend/conf/config.yml @@ -14,13 +14,11 @@ redis: port: 6379 log: level: info - path: "/var/logs/crawlab" - isDeletePeriodically: "N" - deleteFrequency: "@hourly" + path: "/logs" server: host: 0.0.0.0 port: 8000 - master: "Y" + master: true secret: "crawlab" register: # type 填 mac/ip/customName, 如果是ip,则需要手动指定IP, 如果是 customName, 需填写你的 customNodeName @@ -35,9 +33,12 @@ server: php: "N" scripts: "/app/backend/scripts" spider: - path: "/app/spiders" + fs: "/spiders" + workspace: "/workspace" + repo: "/repo" task: workers: 16 + cancelWaitSeconds: 30 other: tmppath: "/tmp" version: 0.5.1 diff --git a/backend/go.mod b/backend/go.mod index de7a5156..d9ef355a 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -5,11 +5,16 @@ go 1.15 replace ( github.com/crawlab-team/crawlab-core => /Users/marvzhang/projects/crawlab-team/crawlab-core github.com/crawlab-team/crawlab-db => /Users/marvzhang/projects/crawlab-team/crawlab-db + github.com/crawlab-team/crawlab-grpc => /Users/marvzhang/projects/crawlab-team/crawlab-grpc/dist/go + github.com/crawlab-team/crawlab-log => /Users/marvzhang/projects/crawlab-team/crawlab-log + github.com/crawlab-team/crawlab-vcs => /Users/marvzhang/projects/crawlab-team/crawlab-vcs + github.com/crawlab-team/crawlab-fs => /Users/marvzhang/projects/crawlab-team/crawlab-fs + github.com/linxGnu/goseaweedfs => /Users/marvzhang/projects/tikazyq/goseaweedfs ) require ( github.com/apex/log v1.9.0 - github.com/crawlab-team/crawlab-core v0.0.0-00010101000000-000000000000 + github.com/crawlab-team/crawlab-core v0.0.1 github.com/crawlab-team/crawlab-db v0.0.2 github.com/gin-gonic/gin v1.6.3 github.com/go-playground/validator/v10 v10.3.0 diff --git a/backend/go.sum b/backend/go.sum index a0c5fc74..98dfcdc3 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -19,6 +19,7 @@ github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Masterminds/sprig v2.16.0+incompatible h1:QZbMUPxRQ50EKAq3LFMnxddMu88/EUUG3qmxwtDmPsY= github.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd h1:+CYOsXi89xOqBkj7CuEJjA2It+j+R3ngUZEydr6mtkw= github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= @@ -49,15 +50,20 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc= github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/crawlab-team/crawlab-fs v0.0.0 h1:RGPWKB7ORgGEYLS5uplS/dIbdY8ktKmfBHM2MxxwQKQ= +github.com/crawlab-team/crawlab-fs v0.0.0/go.mod h1:k2VXprQspLAmbgO5sSpqMjg/xP4iKDkW4RyTWY8eTZM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -66,6 +72,10 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= @@ -84,10 +94,18 @@ github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI= +github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= @@ -116,6 +134,15 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -123,8 +150,10 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -132,6 +161,8 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -167,6 +198,8 @@ github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0 github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U= github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw= github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ= @@ -202,11 +235,16 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/linxGnu/goseaweedfs v0.1.5 h1:7dChPdq8+fsPH0yqxKEofPhiosaar4LWePm4M+1Taz0= +github.com/linxGnu/goseaweedfs v0.1.5/go.mod h1:Zwe/7H7FJaPQyMTNKXgv6fhVDw6qi34MMJQp1K0VLNc= +github.com/linxGnu/gumble v1.0.0 h1:OAJud8Hy4rmV9I5p/KTRiVpwwklMTd9Ankza3Mz7a4M= +github.com/linxGnu/gumble v1.0.0/go.mod h1:iyhNJpBHvJ0q2Hr41iiZRJyj6LLF47i2a9C9zLiucVY= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= @@ -247,6 +285,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -271,6 +310,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -282,9 +322,14 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/scryner/lfreequeue v0.0.0-20121212074822-473f33702129/go.mod h1:0OrdloYlIayHGsgKYlwEnmdrPWmuYtbdS6Dm71PprFM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil v3.20.11+incompatible h1:LJr4ZQK4mPpIV5gOa4jCOKOGb4ty4DZO54I4FGqIpto= +github.com/shirou/gopsutil v3.20.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -336,6 +381,7 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/valyala/fastrand v1.0.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -359,6 +405,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -398,6 +446,9 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smto golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -428,13 +479,21 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg= +golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -447,6 +506,7 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -480,9 +540,26 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= @@ -491,6 +568,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= @@ -524,5 +602,6 @@ gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 9b947c6d565be6362058c11fb8b9516ec414ebe6 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Tue, 23 Mar 2021 22:50:19 +0800 Subject: [PATCH 04/19] refactoring --- backend/go.mod | 4 +- backend/go.sum | 77 +++ backend/main.go | 566 ++++++++++------------- backend/services/api.go | 97 ++++ frontend/src/views/spider/SpiderList.vue | 1 - 5 files changed, 417 insertions(+), 328 deletions(-) create mode 100644 backend/services/api.go diff --git a/backend/go.mod b/backend/go.mod index d9ef355a..f70efcd7 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -5,10 +5,11 @@ go 1.15 replace ( github.com/crawlab-team/crawlab-core => /Users/marvzhang/projects/crawlab-team/crawlab-core github.com/crawlab-team/crawlab-db => /Users/marvzhang/projects/crawlab-team/crawlab-db + github.com/crawlab-team/crawlab-fs => /Users/marvzhang/projects/crawlab-team/crawlab-fs github.com/crawlab-team/crawlab-grpc => /Users/marvzhang/projects/crawlab-team/crawlab-grpc/dist/go github.com/crawlab-team/crawlab-log => /Users/marvzhang/projects/crawlab-team/crawlab-log github.com/crawlab-team/crawlab-vcs => /Users/marvzhang/projects/crawlab-team/crawlab-vcs - github.com/crawlab-team/crawlab-fs => /Users/marvzhang/projects/crawlab-team/crawlab-fs + github.com/crawlab-team/go-trace => /Users/marvzhang/projects/crawlab-team/go-trace github.com/linxGnu/goseaweedfs => /Users/marvzhang/projects/tikazyq/goseaweedfs ) @@ -16,6 +17,7 @@ require ( github.com/apex/log v1.9.0 github.com/crawlab-team/crawlab-core v0.0.1 github.com/crawlab-team/crawlab-db v0.0.2 + github.com/crawlab-team/go-trace v0.0.0 github.com/gin-gonic/gin v1.6.3 github.com/go-playground/validator/v10 v10.3.0 github.com/olivere/elastic/v7 v7.0.15 diff --git a/backend/go.sum b/backend/go.sum index 98dfcdc3..b60adc4f 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -43,6 +43,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.30.7/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -119,7 +121,32 @@ github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -143,6 +170,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -154,6 +183,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -202,6 +232,7 @@ github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U= github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ= github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= @@ -209,8 +240,12 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= @@ -221,11 +256,16 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -245,10 +285,14 @@ github.com/linxGnu/goseaweedfs v0.1.5 h1:7dChPdq8+fsPH0yqxKEofPhiosaar4LWePm4M+1 github.com/linxGnu/goseaweedfs v0.1.5/go.mod h1:Zwe/7H7FJaPQyMTNKXgv6fhVDw6qi34MMJQp1K0VLNc= github.com/linxGnu/gumble v1.0.0 h1:OAJud8Hy4rmV9I5p/KTRiVpwwklMTd9Ankza3Mz7a4M= github.com/linxGnu/gumble v1.0.0/go.mod h1:iyhNJpBHvJ0q2Hr41iiZRJyj6LLF47i2a9C9zLiucVY= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/matcornic/hermes v1.2.0 h1:AuqZpYcTOtTB7cahdevLfnhIpfzmpqw5Czv8vpdnFDU= github.com/matcornic/hermes v1.2.0/go.mod h1:lujJomb016Xjv8wBnWlNvUdtmvowjjfkqri5J/+1hYc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -284,6 +328,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -298,6 +343,8 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -316,8 +363,12 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= @@ -333,6 +384,9 @@ github.com/shirou/gopsutil v3.20.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMT github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= @@ -346,6 +400,7 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= @@ -369,6 +424,7 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= @@ -384,8 +440,16 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/valyala/fastrand v1.0.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= +github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.mongodb.org/mongo-driver v1.4.5 h1:TLtO+iD8krabXxvY1F1qpBOHgOxhLWR7XsT7kQeRmMY= +go.mongodb.org/mongo-driver v1.4.5/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -399,9 +463,11 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -456,7 +522,10 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -468,10 +537,14 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0= @@ -504,9 +577,13 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= diff --git a/backend/main.go b/backend/main.go index 8832bad7..33c1d00d 100644 --- a/backend/main.go +++ b/backend/main.go @@ -1,338 +1,252 @@ package main -import ( - "context" - "github.com/apex/log" - "github.com/crawlab-team/crawlab-core/config" - validate2 "github.com/crawlab-team/crawlab-core/lib/validate" - "github.com/crawlab-team/crawlab-core/middlewares" - "github.com/crawlab-team/crawlab-core/model" - "github.com/crawlab-team/crawlab-core/routes" - "github.com/crawlab-team/crawlab-core/services" - "github.com/crawlab-team/crawlab-core/services/rpc" - "github.com/crawlab-team/crawlab-db" - "github.com/gin-gonic/gin" - "github.com/gin-gonic/gin/binding" - "github.com/go-playground/validator/v10" - "github.com/olivere/elastic/v7" - "github.com/spf13/viper" - "net" - "net/http" - "os" - "os/signal" - "runtime/debug" - "syscall" - "time" -) +import "crawlab/services" func main() { - app := gin.New() - app.Use(gin.Logger(), gin.Recovery()) - if v, ok := binding.Validator.Engine().(*validator.Validate); ok { - _ = v.RegisterValidation("bid", validate2.MongoID) - } + api := services.NewApiService() + api.Init() + api.Run() - // 初始化配置 - if err := config.InitConfig(""); err != nil { - log.Error("init config error:" + err.Error()) - panic(err) - } - log.Info("initialized config successfully") - // 初始化Mongodb数据库 - if err := db.InitMongo(); err != nil { - log.Error("init mongodb error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized mongodb successfully") - - // 初始化Redis数据库 - if err := db.InitRedis(); err != nil { - log.Error("init redis error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized redis successfully") - - // 初始化日志设置 - if err := services.InitLogService(); err != nil { - log.Error("init log error:" + err.Error()) - panic(err) - } - log.Info("initialized log successfully") // 初始化日志设置 - - // 初始化节点服务 - if err := services.InitNodeService(); err != nil { - log.Error("init node service error:" + err.Error()) - panic(err) - } - log.Info("initialized local node successfully") - - if model.IsMaster() { - - // 初始化定时任务 - if err := services.InitScheduler(); err != nil { - log.Error("init scheduler error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized schedule successfully") - - // 初始化用户服务 - if err := services.InitUserService(); err != nil { - log.Error("init user service error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized user service successfully") - - // 初始化依赖服务 - if err := services.InitDepsFetcher(); err != nil { - log.Error("init dependency fetcher error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized dependency fetcher successfully") - - // 初始化清理服务 - if err := services.InitCleanService(); err != nil { - log.Error("init clean service error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized clean service successfully") - } - - // 初始化任务执行器 - if err := services.InitTaskExecutor(); err != nil { - log.Error("init task executor error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized task executor successfully") - - // 初始化爬虫服务 - if err := services.InitSpiderService(); err != nil { - log.Error("init spider service error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized spider service successfully") - - // 初始化RPC服务 - if err := rpc.InitRpcService(); err != nil { - log.Error("init rpc service error:" + err.Error()) - debug.PrintStack() - panic(err) - } - log.Info("initialized rpc service successfully") + //if model.IsMaster() { + // // 初始化定时任务 + // if err := services.InitScheduler(); err != nil { + // log.Error("init scheduler error:" + err.Error()) + // debug.PrintStack() + // panic(err) + // } + // log.Info("initialized schedule successfully") + // + // // 初始化用户服务 + // if err := services.InitUserService(); err != nil { + // log.Error("init user service error:" + err.Error()) + // debug.PrintStack() + // panic(err) + // } + // log.Info("initialized user service successfully") + // + // // 初始化依赖服务 + // if err := services.InitDepsFetcher(); err != nil { + // log.Error("init dependency fetcher error:" + err.Error()) + // debug.PrintStack() + // panic(err) + // } + // log.Info("initialized dependency fetcher successfully") + // + // // 初始化清理服务 + // if err := services.InitCleanService(); err != nil { + // log.Error("init clean service error:" + err.Error()) + // debug.PrintStack() + // panic(err) + // } + // log.Info("initialized clean service successfully") + //} + // + //// 初始化任务执行器 + //if err := services.InitTaskExecutor(); err != nil { + // log.Error("init task executor error:" + err.Error()) + // debug.PrintStack() + // panic(err) + //} + //log.Info("initialized task executor successfully") + // + //// 初始化爬虫服务 + //if err := services.InitSpiderService(); err != nil { + // log.Error("init spider service error:" + err.Error()) + // debug.PrintStack() + // panic(err) + //} + //log.Info("initialized spider service successfully") + // + //// 初始化RPC服务 + //if err := rpc.InitRpcService(); err != nil { + // log.Error("init rpc service error:" + err.Error()) + // debug.PrintStack() + // panic(err) + //} + //log.Info("initialized rpc service successfully") // 以下为主节点服务 - if model.IsMaster() { - // 中间件 - esClientStr := viper.GetString("setting.esClient") - if viper.GetString("setting.crawlabLogToES") == "Y" && esClientStr != "" { - ctx := context.Background() - esClient, err := elastic.NewClient(elastic.SetURL(esClientStr), elastic.SetSniff(false)) - if err != nil { - log.Error("Init es client Error:" + err.Error()) - } - app.Use(middlewares.EsLog(ctx, esClient)) - } - app.Use(middlewares.CORSMiddleware()) - anonymousGroup := app.Group("/") - { - anonymousGroup.POST("/login", routes.Login) // 用户登录 - anonymousGroup.PUT("/users", routes.PutUser) // 添加用户 - anonymousGroup.GET("/setting", routes.GetSetting) // 获取配置信息 - // release版本 - anonymousGroup.GET("/version", routes.GetVersion) // 获取发布的版本 - anonymousGroup.GET("/releases/latest", routes.GetLatestRelease) // 获取最近发布的版本 - // 文档 - anonymousGroup.GET("/docs", routes.GetDocs) // 获取文档数据 - } - authGroup := app.Group("/", middlewares.AuthorizationMiddleware()) - { - // 节点 - { - authGroup.GET("/nodes", routes.GetNodeList) // 节点列表 - authGroup.GET("/nodes/:id", routes.GetNode) // 节点详情 - authGroup.POST("/nodes/:id", routes.PostNode) // 修改节点 - authGroup.GET("/nodes/:id/tasks", routes.GetNodeTaskList) // 节点任务列表 - authGroup.GET("/nodes/:id/system", routes.GetSystemInfo) // 节点任务列表 - authGroup.DELETE("/nodes/:id", routes.DeleteNode) // 删除节点 - authGroup.GET("/nodes/:id/langs", routes.GetLangList) // 节点语言环境列表 - authGroup.GET("/nodes/:id/deps", routes.GetDepList) // 节点第三方依赖列表 - authGroup.GET("/nodes/:id/deps/installed", routes.GetInstalledDepList) // 节点已安装第三方依赖列表 - authGroup.POST("/nodes/:id/deps/install", routes.InstallDep) // 节点安装依赖 - authGroup.POST("/nodes/:id/deps/uninstall", routes.UninstallDep) // 节点卸载依赖 - authGroup.POST("/nodes/:id/langs/install", routes.InstallLang) // 节点安装语言 - } - // 爬虫 - { - authGroup.GET("/spiders", routes.GetSpiderList) // 爬虫列表 - authGroup.GET("/spiders/:id", routes.GetSpider) // 爬虫详情 - authGroup.PUT("/spiders", routes.PutSpider) // 添加爬虫 - authGroup.POST("/spiders", routes.UploadSpider) // 上传爬虫 - authGroup.POST("/spiders/:id", routes.PostSpider) // 修改爬虫 - authGroup.POST("/spiders/:id/publish", routes.PublishSpider) // 发布爬虫 - authGroup.POST("/spiders/:id/upload", routes.UploadSpiderFromId) // 上传爬虫(ID) - authGroup.DELETE("/spiders", routes.DeleteSelectedSpider) // 删除选择的爬虫 - authGroup.DELETE("/spiders/:id", routes.DeleteSpider) // 删除爬虫 - authGroup.POST("/spiders/:id/copy", routes.CopySpider) // 拷贝爬虫 - authGroup.GET("/spiders/:id/tasks", routes.GetSpiderTasks) // 爬虫任务列表 - authGroup.GET("/spiders/:id/file/tree", routes.GetSpiderFileTree) // 爬虫文件目录树读取 - authGroup.GET("/spiders/:id/file", routes.GetSpiderFile) // 爬虫文件读取 - authGroup.POST("/spiders/:id/file", routes.PostSpiderFile) // 爬虫文件更改 - authGroup.PUT("/spiders/:id/file", routes.PutSpiderFile) // 爬虫文件创建 - authGroup.PUT("/spiders/:id/dir", routes.PutSpiderDir) // 爬虫目录创建 - authGroup.DELETE("/spiders/:id/file", routes.DeleteSpiderFile) // 爬虫文件删除 - authGroup.POST("/spiders/:id/file/rename", routes.RenameSpiderFile) // 爬虫文件重命名 - authGroup.GET("/spiders/:id/dir", routes.GetSpiderDir) // 爬虫目录 - authGroup.GET("/spiders/:id/stats", routes.GetSpiderStats) // 爬虫统计数据 - authGroup.GET("/spiders/:id/schedules", routes.GetSpiderSchedules) // 爬虫定时任务 - authGroup.GET("/spiders/:id/scrapy/spiders", routes.GetSpiderScrapySpiders) // Scrapy 爬虫名称列表 - authGroup.PUT("/spiders/:id/scrapy/spiders", routes.PutSpiderScrapySpiders) // Scrapy 爬虫创建爬虫 - authGroup.GET("/spiders/:id/scrapy/settings", routes.GetSpiderScrapySettings) // Scrapy 爬虫设置 - authGroup.POST("/spiders/:id/scrapy/settings", routes.PostSpiderScrapySettings) // Scrapy 爬虫修改设置 - authGroup.GET("/spiders/:id/scrapy/items", routes.GetSpiderScrapyItems) // Scrapy 爬虫 items - authGroup.POST("/spiders/:id/scrapy/items", routes.PostSpiderScrapyItems) // Scrapy 爬虫修改 items - authGroup.GET("/spiders/:id/scrapy/pipelines", routes.GetSpiderScrapyPipelines) // Scrapy 爬虫 pipelines - authGroup.GET("/spiders/:id/scrapy/spider/filepath", routes.GetSpiderScrapySpiderFilepath) // Scrapy 爬虫 pipelines - authGroup.POST("/spiders/:id/git/sync", routes.PostSpiderSyncGit) // 爬虫 Git 同步 - authGroup.POST("/spiders/:id/git/reset", routes.PostSpiderResetGit) // 爬虫 Git 重置 - authGroup.POST("/spiders-cancel", routes.CancelSelectedSpider) // 停止所选爬虫任务 - authGroup.POST("/spiders-run", routes.RunSelectedSpider) // 运行所选爬虫 - authGroup.POST("/spiders-set-projects", routes.SetProjectsSelectedSpider) // 批量设置爬虫项目 - } - // 可配置爬虫 - { - authGroup.GET("/config_spiders/:id/config", routes.GetConfigSpiderConfig) // 获取可配置爬虫配置 - authGroup.POST("/config_spiders/:id/config", routes.PostConfigSpiderConfig) // 更改可配置爬虫配置 - authGroup.PUT("/config_spiders", routes.PutConfigSpider) // 添加可配置爬虫 - authGroup.POST("/config_spiders/:id", routes.PostConfigSpider) // 修改可配置爬虫 - authGroup.POST("/config_spiders/:id/upload", routes.UploadConfigSpider) // 上传可配置爬虫 - authGroup.POST("/config_spiders/:id/spiderfile", routes.PostConfigSpiderSpiderfile) // 上传可配置爬虫 - authGroup.GET("/config_spiders_templates", routes.GetConfigSpiderTemplateList) // 获取可配置爬虫模版列表 - } - // 任务 - { - authGroup.GET("/tasks", routes.GetTaskList) // 任务列表 - authGroup.GET("/tasks/:id", routes.GetTask) // 任务详情 - authGroup.PUT("/tasks", routes.PutTask) // 派发任务 - authGroup.PUT("/tasks/batch", routes.PutBatchTasks) // 批量派发任务 - authGroup.DELETE("/tasks/:id", routes.DeleteTask) // 删除任务 - authGroup.DELETE("/tasks", routes.DeleteSelectedTask) // 删除多个任务 - //authGroup.DELETE("/tasks_by_status", routes.DeleteTaskByStatus) // 删除指定状态的任务 - authGroup.POST("/tasks/:id/cancel", routes.CancelTask) // 取消任务 - authGroup.GET("/tasks/:id/log", routes.GetTaskLog) // 任务日志 - authGroup.GET("/tasks/:id/error-log", routes.GetTaskErrorLog) // 任务错误日志 - authGroup.GET("/tasks/:id/results", routes.GetTaskResults) // 任务结果 - authGroup.GET("/tasks/:id/results/download", routes.DownloadTaskResultsCsv) // 下载任务结果 - authGroup.POST("/tasks/:id/restart", routes.RestartTask) // 重新开始任务 - authGroup.POST("/tasks-cancel", routes.CancelSelectedTask) // 批量取消任务 - authGroup.POST("/tasks-restart", routes.RestartSelectedTask) // 批量重试任务 - } - // 系统任务/脚本 - { - authGroup.PUT("/system-tasks", routes.PutSystemTask) // 运行系统任务 - authGroup.GET("/system-scripts", routes.GetSystemScripts) // 获取系统脚本列表 - } - // 定时任务 - { - authGroup.GET("/schedules", routes.GetScheduleList) // 定时任务列表 - authGroup.GET("/schedules/:id", routes.GetSchedule) // 定时任务详情 - authGroup.PUT("/schedules", routes.PutSchedule) // 创建定时任务 - authGroup.PUT("/schedules/batch", routes.PutBatchSchedules) // 批量创建定时任务 - authGroup.POST("/schedules/:id", routes.PostSchedule) // 修改定时任务 - authGroup.DELETE("/schedules/:id", routes.DeleteSchedule) // 删除定时任务 - authGroup.DELETE("/schedules", routes.DeleteBatchSchedules) // 批量删除定时任务 - authGroup.POST("/schedules/:id/disable", routes.DisableSchedule) // 禁用定时任务 - authGroup.POST("/schedules/:id/enable", routes.EnableSchedule) // 启用定时任务 - authGroup.POST("/schedules-set-enabled", routes.SetEnabledSchedules) // 批量设置定时任务状态 - } - // 用户 - { - authGroup.GET("/users", routes.GetUserList) // 用户列表 - authGroup.GET("/users/:id", routes.GetUser) // 用户详情 - authGroup.POST("/users/:id", routes.PostUser) // 更改用户 - authGroup.DELETE("/users/:id", routes.DeleteUser) // 删除用户 - authGroup.PUT("/users-add", routes.PutUser) // 添加用户 - authGroup.GET("/me", routes.GetMe) // 获取自己账户 - authGroup.POST("/me", routes.PostMe) // 修改自己账户 - authGroup.POST("/me/change-password", routes.PostMeChangePassword) // 修改自己密码 - } - // 系统 - { - authGroup.GET("/system/deps/:lang", routes.GetAllDepList) // 节点所有第三方依赖列表 - authGroup.GET("/system/deps/:lang/:dep_name/json", routes.GetDepJson) // 节点第三方依赖JSON - } - // 全局变量 - { - authGroup.GET("/variables", routes.GetVariableList) // 列表 - authGroup.PUT("/variable", routes.PutVariable) // 新增 - authGroup.POST("/variable/:id", routes.PostVariable) // 修改 - authGroup.DELETE("/variable/:id", routes.DeleteVariable) // 删除 - } - // 项目 - { - authGroup.GET("/projects", routes.GetProjectList) // 列表 - authGroup.GET("/projects/tags", routes.GetProjectTags) // 项目标签 - authGroup.PUT("/projects", routes.PutProject) // 修改 - authGroup.POST("/projects/:id", routes.PostProject) // 新增 - authGroup.DELETE("/projects/:id", routes.DeleteProject) // 删除 - } - // 操作 - { - //authGroup.GET("/actions", routes.GetActionList) // 操作列表 - //authGroup.GET("/actions/:id", routes.GetAction) // 操作 - authGroup.PUT("/actions", routes.PutAction) // 新增操作 - //authGroup.POST("/actions/:id", routes.PostAction) // 修改操作 - } - // API Token - { - authGroup.GET("/tokens", routes.GetTokens) // 获取 Tokens - authGroup.PUT("/tokens", routes.PutToken) // 添加 Token - authGroup.DELETE("/tokens/:id", routes.DeleteToken) // 删除 Token - } - // 统计数据 - authGroup.GET("/stats/home", routes.GetHomeStats) // 首页统计数据 - // 文件 - authGroup.GET("/file", routes.GetFile) // 获取文件 - // Git - authGroup.GET("/git/branches", routes.GetGitRemoteBranches) // 获取 Git 分支 - authGroup.GET("/git/public-key", routes.GetGitSshPublicKey) // 获取 SSH 公钥 - authGroup.GET("/git/commits", routes.GetGitCommits) // 获取 Git Commits - authGroup.POST("/git/checkout", routes.PostGitCheckout) // 获取 Git Commits - } - } + //if model.IsMaster() { + // // 中间件 + // esClientStr := viper.GetString("setting.esClient") + // if viper.GetString("setting.crawlabLogToES") == "Y" && esClientStr != "" { + // ctx := context.Background() + // esClient, err := elastic.NewClient(elastic.SetURL(esClientStr), elastic.SetSniff(false)) + // if err != nil { + // log.Error("Init es client Error:" + err.Error()) + // } + // app.Use(middlewares.EsLog(ctx, esClient)) + // } + // app.Use(middlewares.CORSMiddleware()) + // anonymousGroup := app.Group("/") + // { + // anonymousGroup.POST("/login", routes.Login) // 用户登录 + // anonymousGroup.PUT("/users", routes.PutUser) // 添加用户 + // anonymousGroup.GET("/setting", routes.GetSetting) // 获取配置信息 + // // release版本 + // anonymousGroup.GET("/version", routes.GetVersion) // 获取发布的版本 + // anonymousGroup.GET("/releases/latest", routes.GetLatestRelease) // 获取最近发布的版本 + // // 文档 + // anonymousGroup.GET("/docs", routes.GetDocs) // 获取文档数据 + // } + // authGroup := app.Group("/", middlewares.AuthorizationMiddleware()) + // { + // // 节点 + // { + // authGroup.GET("/nodes", routes.GetNodeList) // 节点列表 + // authGroup.GET("/nodes/:id", routes.GetNode) // 节点详情 + // authGroup.POST("/nodes/:id", routes.PostNode) // 修改节点 + // authGroup.GET("/nodes/:id/tasks", routes.GetNodeTaskList) // 节点任务列表 + // authGroup.GET("/nodes/:id/system", routes.GetSystemInfo) // 节点任务列表 + // authGroup.DELETE("/nodes/:id", routes.DeleteNode) // 删除节点 + // authGroup.GET("/nodes/:id/langs", routes.GetLangList) // 节点语言环境列表 + // authGroup.GET("/nodes/:id/deps", routes.GetDepList) // 节点第三方依赖列表 + // authGroup.GET("/nodes/:id/deps/installed", routes.GetInstalledDepList) // 节点已安装第三方依赖列表 + // authGroup.POST("/nodes/:id/deps/install", routes.InstallDep) // 节点安装依赖 + // authGroup.POST("/nodes/:id/deps/uninstall", routes.UninstallDep) // 节点卸载依赖 + // authGroup.POST("/nodes/:id/langs/install", routes.InstallLang) // 节点安装语言 + // } + // // 爬虫 + // { + // authGroup.GET("/spiders", routes.GetSpiderList) // 爬虫列表 + // authGroup.GET("/spiders/:id", routes.GetSpider) // 爬虫详情 + // authGroup.PUT("/spiders", routes.PutSpider) // 添加爬虫 + // authGroup.POST("/spiders", routes.UploadSpider) // 上传爬虫 + // authGroup.POST("/spiders/:id", routes.PostSpider) // 修改爬虫 + // authGroup.POST("/spiders/:id/publish", routes.PublishSpider) // 发布爬虫 + // authGroup.POST("/spiders/:id/upload", routes.UploadSpiderFromId) // 上传爬虫(ID) + // authGroup.DELETE("/spiders", routes.DeleteSelectedSpider) // 删除选择的爬虫 + // authGroup.DELETE("/spiders/:id", routes.DeleteSpider) // 删除爬虫 + // authGroup.POST("/spiders/:id/copy", routes.CopySpider) // 拷贝爬虫 + // authGroup.GET("/spiders/:id/tasks", routes.GetSpiderTasks) // 爬虫任务列表 + // authGroup.GET("/spiders/:id/file/tree", routes.GetSpiderFileTree) // 爬虫文件目录树读取 + // authGroup.GET("/spiders/:id/file", routes.GetSpiderFile) // 爬虫文件读取 + // authGroup.POST("/spiders/:id/file", routes.PostSpiderFile) // 爬虫文件更改 + // authGroup.PUT("/spiders/:id/file", routes.PutSpiderFile) // 爬虫文件创建 + // authGroup.PUT("/spiders/:id/dir", routes.PutSpiderDir) // 爬虫目录创建 + // authGroup.DELETE("/spiders/:id/file", routes.DeleteSpiderFile) // 爬虫文件删除 + // authGroup.POST("/spiders/:id/file/rename", routes.RenameSpiderFile) // 爬虫文件重命名 + // authGroup.GET("/spiders/:id/dir", routes.GetSpiderDir) // 爬虫目录 + // authGroup.GET("/spiders/:id/stats", routes.GetSpiderStats) // 爬虫统计数据 + // authGroup.GET("/spiders/:id/schedules", routes.GetSpiderSchedules) // 爬虫定时任务 + // authGroup.GET("/spiders/:id/scrapy/spiders", routes.GetSpiderScrapySpiders) // Scrapy 爬虫名称列表 + // authGroup.PUT("/spiders/:id/scrapy/spiders", routes.PutSpiderScrapySpiders) // Scrapy 爬虫创建爬虫 + // authGroup.GET("/spiders/:id/scrapy/settings", routes.GetSpiderScrapySettings) // Scrapy 爬虫设置 + // authGroup.POST("/spiders/:id/scrapy/settings", routes.PostSpiderScrapySettings) // Scrapy 爬虫修改设置 + // authGroup.GET("/spiders/:id/scrapy/items", routes.GetSpiderScrapyItems) // Scrapy 爬虫 items + // authGroup.POST("/spiders/:id/scrapy/items", routes.PostSpiderScrapyItems) // Scrapy 爬虫修改 items + // authGroup.GET("/spiders/:id/scrapy/pipelines", routes.GetSpiderScrapyPipelines) // Scrapy 爬虫 pipelines + // authGroup.GET("/spiders/:id/scrapy/spider/filepath", routes.GetSpiderScrapySpiderFilepath) // Scrapy 爬虫 pipelines + // authGroup.POST("/spiders/:id/git/sync", routes.PostSpiderSyncGit) // 爬虫 Git 同步 + // authGroup.POST("/spiders/:id/git/reset", routes.PostSpiderResetGit) // 爬虫 Git 重置 + // authGroup.POST("/spiders-cancel", routes.CancelSelectedSpider) // 停止所选爬虫任务 + // authGroup.POST("/spiders-run", routes.RunSelectedSpider) // 运行所选爬虫 + // authGroup.POST("/spiders-set-projects", routes.SetProjectsSelectedSpider) // 批量设置爬虫项目 + // } + // // 可配置爬虫 + // { + // authGroup.GET("/config_spiders/:id/config", routes.GetConfigSpiderConfig) // 获取可配置爬虫配置 + // authGroup.POST("/config_spiders/:id/config", routes.PostConfigSpiderConfig) // 更改可配置爬虫配置 + // authGroup.PUT("/config_spiders", routes.PutConfigSpider) // 添加可配置爬虫 + // authGroup.POST("/config_spiders/:id", routes.PostConfigSpider) // 修改可配置爬虫 + // authGroup.POST("/config_spiders/:id/upload", routes.UploadConfigSpider) // 上传可配置爬虫 + // authGroup.POST("/config_spiders/:id/spiderfile", routes.PostConfigSpiderSpiderfile) // 上传可配置爬虫 + // authGroup.GET("/config_spiders_templates", routes.GetConfigSpiderTemplateList) // 获取可配置爬虫模版列表 + // } + // // 任务 + // { + // authGroup.GET("/tasks", routes.GetTaskList) // 任务列表 + // authGroup.GET("/tasks/:id", routes.GetTask) // 任务详情 + // authGroup.PUT("/tasks", routes.PutTask) // 派发任务 + // authGroup.PUT("/tasks/batch", routes.PutBatchTasks) // 批量派发任务 + // authGroup.DELETE("/tasks/:id", routes.DeleteTask) // 删除任务 + // authGroup.DELETE("/tasks", routes.DeleteSelectedTask) // 删除多个任务 + // //authGroup.DELETE("/tasks_by_status", routes.DeleteTaskByStatus) // 删除指定状态的任务 + // authGroup.POST("/tasks/:id/cancel", routes.CancelTask) // 取消任务 + // authGroup.GET("/tasks/:id/log", routes.GetTaskLog) // 任务日志 + // authGroup.GET("/tasks/:id/error-log", routes.GetTaskErrorLog) // 任务错误日志 + // authGroup.GET("/tasks/:id/results", routes.GetTaskResults) // 任务结果 + // authGroup.GET("/tasks/:id/results/download", routes.DownloadTaskResultsCsv) // 下载任务结果 + // authGroup.POST("/tasks/:id/restart", routes.RestartTask) // 重新开始任务 + // authGroup.POST("/tasks-cancel", routes.CancelSelectedTask) // 批量取消任务 + // authGroup.POST("/tasks-restart", routes.RestartSelectedTask) // 批量重试任务 + // } + // // 系统任务/脚本 + // { + // authGroup.PUT("/system-tasks", routes.PutSystemTask) // 运行系统任务 + // authGroup.GET("/system-scripts", routes.GetSystemScripts) // 获取系统脚本列表 + // } + // // 定时任务 + // { + // authGroup.GET("/schedules", routes.GetScheduleList) // 定时任务列表 + // authGroup.GET("/schedules/:id", routes.GetSchedule) // 定时任务详情 + // authGroup.PUT("/schedules", routes.PutSchedule) // 创建定时任务 + // authGroup.PUT("/schedules/batch", routes.PutBatchSchedules) // 批量创建定时任务 + // authGroup.POST("/schedules/:id", routes.PostSchedule) // 修改定时任务 + // authGroup.DELETE("/schedules/:id", routes.DeleteSchedule) // 删除定时任务 + // authGroup.DELETE("/schedules", routes.DeleteBatchSchedules) // 批量删除定时任务 + // authGroup.POST("/schedules/:id/disable", routes.DisableSchedule) // 禁用定时任务 + // authGroup.POST("/schedules/:id/enable", routes.EnableSchedule) // 启用定时任务 + // authGroup.POST("/schedules-set-enabled", routes.SetEnabledSchedules) // 批量设置定时任务状态 + // } + // // 用户 + // { + // authGroup.GET("/users", routes.GetUserList) // 用户列表 + // authGroup.GET("/users/:id", routes.GetUser) // 用户详情 + // authGroup.POST("/users/:id", routes.PostUser) // 更改用户 + // authGroup.DELETE("/users/:id", routes.DeleteUser) // 删除用户 + // authGroup.PUT("/users-add", routes.PutUser) // 添加用户 + // authGroup.GET("/me", routes.GetMe) // 获取自己账户 + // authGroup.POST("/me", routes.PostMe) // 修改自己账户 + // authGroup.POST("/me/change-password", routes.PostMeChangePassword) // 修改自己密码 + // } + // // 系统 + // { + // authGroup.GET("/system/deps/:lang", routes.GetAllDepList) // 节点所有第三方依赖列表 + // authGroup.GET("/system/deps/:lang/:dep_name/json", routes.GetDepJson) // 节点第三方依赖JSON + // } + // // 全局变量 + // { + // authGroup.GET("/variables", routes.GetVariableList) // 列表 + // authGroup.PUT("/variable", routes.PutVariable) // 新增 + // authGroup.POST("/variable/:id", routes.PostVariable) // 修改 + // authGroup.DELETE("/variable/:id", routes.DeleteVariable) // 删除 + // } + // // 项目 + // { + // authGroup.GET("/projects", routes.GetProjectList) // 列表 + // authGroup.GET("/projects/tags", routes.GetProjectTags) // 项目标签 + // authGroup.PUT("/projects", routes.PutProject) // 修改 + // authGroup.POST("/projects/:id", routes.PostProject) // 新增 + // authGroup.DELETE("/projects/:id", routes.DeleteProject) // 删除 + // } + // // 操作 + // { + // //authGroup.GET("/actions", routes.GetActionList) // 操作列表 + // //authGroup.GET("/actions/:id", routes.GetAction) // 操作 + // authGroup.PUT("/actions", routes.PutAction) // 新增操作 + // //authGroup.POST("/actions/:id", routes.PostAction) // 修改操作 + // } + // // API Token + // { + // authGroup.GET("/tokens", routes.GetTokens) // 获取 Tokens + // authGroup.PUT("/tokens", routes.PutToken) // 添加 Token + // authGroup.DELETE("/tokens/:id", routes.DeleteToken) // 删除 Token + // } + // // 统计数据 + // authGroup.GET("/stats/home", routes.GetHomeStats) // 首页统计数据 + // // 文件 + // authGroup.GET("/file", routes.GetFile) // 获取文件 + // // Git + // authGroup.GET("/git/branches", routes.GetGitRemoteBranches) // 获取 Git 分支 + // authGroup.GET("/git/public-key", routes.GetGitSshPublicKey) // 获取 SSH 公钥 + // authGroup.GET("/git/commits", routes.GetGitCommits) // 获取 Git Commits + // authGroup.POST("/git/checkout", routes.PostGitCheckout) // 获取 Git Commits + // } + //} // 路由ping - app.GET("/ping", routes.Ping) + //app.GET("/ping", routes.Ping) // 运行服务器 - host := viper.GetString("server.host") - port := viper.GetString("server.port") - address := net.JoinHostPort(host, port) - srv := &http.Server{ - Handler: app, - Addr: address, - } - go func() { - if err := srv.ListenAndServe(); err != nil { - if err != http.ErrServerClosed { - log.Error("run server error:" + err.Error()) - } else { - log.Info("server graceful down") - } - } - }() - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit - ctx2, cancel := context.WithTimeout(context.Background(), 20*time.Second) - defer cancel() - if err := srv.Shutdown(ctx2); err != nil { - log.Error("run server error:" + err.Error()) - } } diff --git a/backend/services/api.go b/backend/services/api.go new file mode 100644 index 00000000..c9846321 --- /dev/null +++ b/backend/services/api.go @@ -0,0 +1,97 @@ +package services + +import ( + "context" + "fmt" + "github.com/apex/log" + "github.com/crawlab-team/crawlab-core/config" + "github.com/crawlab-team/crawlab-core/middlewares" + "github.com/crawlab-team/crawlab-core/routes" + "github.com/crawlab-team/crawlab-db/mongo" + "github.com/crawlab-team/crawlab-db/redis" + "github.com/crawlab-team/go-trace" + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "net" + "net/http" + "os" + "os/signal" + "syscall" + "time" +) + +type ApiInterface interface { + Init() + Run() +} + +type ApiService struct { + app *gin.Engine +} + +func (svc *ApiService) Init() { + // initialize config + _ = svc.initService("config", config.InitConfig) + + // initialize mongo + _ = svc.initService("mongo", mongo.InitMongo) + + // initialize redis + _ = svc.initService("redis", redis.InitRedis) + + // initialize middlewares + _ = svc.initServiceWithApp("middlewares", middlewares.InitMiddlewares) + + // initialize routes + _ = svc.initServiceWithApp("routes", routes.InitRoutes) +} + +func (svc *ApiService) Run() { + host := viper.GetString("server.host") + port := viper.GetString("server.port") + address := net.JoinHostPort(host, port) + srv := &http.Server{ + Handler: svc.app, + Addr: address, + } + go func() { + if err := srv.ListenAndServe(); err != nil { + if err != http.ErrServerClosed { + log.Error("run server error:" + err.Error()) + } else { + log.Info("server graceful down") + } + } + }() + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit + ctx2, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + if err := srv.Shutdown(ctx2); err != nil { + log.Error("run server error:" + err.Error()) + } +} + +func (svc *ApiService) initServiceWithApp(name string, fn func(app *gin.Engine) error) (err error) { + return svc.initService(name, func() error { + return fn(svc.app) + }) +} + +func (svc *ApiService) initService(name string, fn func() error) (err error) { + if err := fn(); err != nil { + log.Error(fmt.Sprintf("init %s error: %s", name, err.Error())) + _ = trace.TraceError(err) + panic(err) + } + log.Info(fmt.Sprintf("initialized %s successfully", name)) + return nil +} + +func NewApiService() *ApiService { + app := gin.New() + return &ApiService{ + app: app, + } +} diff --git a/frontend/src/views/spider/SpiderList.vue b/frontend/src/views/spider/SpiderList.vue index ce945609..10230199 100644 --- a/frontend/src/views/spider/SpiderList.vue +++ b/frontend/src/views/spider/SpiderList.vue @@ -24,7 +24,6 @@ > - From 4ceb2d173eb87326f34bda94dad31bb84f63dedf Mon Sep 17 00:00:00 2001 From: marvzhang Date: Wed, 7 Apr 2021 11:25:00 +0800 Subject: [PATCH 05/19] renamed modules --- backend/{services => apps}/api.go | 21 ++++++++------------- backend/apps/base.go | 6 ++++++ backend/go.sum | 25 +++++++++++++++++++++++++ backend/main.go | 4 ++-- 4 files changed, 41 insertions(+), 15 deletions(-) rename backend/{services => apps}/api.go (82%) create mode 100644 backend/apps/base.go diff --git a/backend/services/api.go b/backend/apps/api.go similarity index 82% rename from backend/services/api.go rename to backend/apps/api.go index c9846321..5fbd67e7 100644 --- a/backend/services/api.go +++ b/backend/apps/api.go @@ -1,4 +1,4 @@ -package services +package apps import ( "context" @@ -20,16 +20,11 @@ import ( "time" ) -type ApiInterface interface { - Init() - Run() -} - -type ApiService struct { +type Api struct { app *gin.Engine } -func (svc *ApiService) Init() { +func (svc *Api) Init() { // initialize config _ = svc.initService("config", config.InitConfig) @@ -46,7 +41,7 @@ func (svc *ApiService) Init() { _ = svc.initServiceWithApp("routes", routes.InitRoutes) } -func (svc *ApiService) Run() { +func (svc *Api) Run() { host := viper.GetString("server.host") port := viper.GetString("server.port") address := net.JoinHostPort(host, port) @@ -73,13 +68,13 @@ func (svc *ApiService) Run() { } } -func (svc *ApiService) initServiceWithApp(name string, fn func(app *gin.Engine) error) (err error) { +func (svc *Api) initServiceWithApp(name string, fn func(app *gin.Engine) error) (err error) { return svc.initService(name, func() error { return fn(svc.app) }) } -func (svc *ApiService) initService(name string, fn func() error) (err error) { +func (svc *Api) initService(name string, fn func() error) (err error) { if err := fn(); err != nil { log.Error(fmt.Sprintf("init %s error: %s", name, err.Error())) _ = trace.TraceError(err) @@ -89,9 +84,9 @@ func (svc *ApiService) initService(name string, fn func() error) (err error) { return nil } -func NewApiService() *ApiService { +func NewApi() *Api { app := gin.New() - return &ApiService{ + return &Api{ app: app, } } diff --git a/backend/apps/base.go b/backend/apps/base.go new file mode 100644 index 00000000..2eb759f4 --- /dev/null +++ b/backend/apps/base.go @@ -0,0 +1,6 @@ +package apps + +type App interface { + Init() + Run() +} diff --git a/backend/go.sum b/backend/go.sum index b60adc4f..776c8761 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -22,6 +22,7 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd h1:+CYOsXi89xOqBkj7CuEJjA2It+j+R3ngUZEydr6mtkw= github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= @@ -78,7 +79,9 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fasthttp/websocket v1.4.2/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -87,6 +90,7 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gavv/httpexpect/v2 v2.2.0/go.mod h1:lnd0TqJLrP+wkJk3SFwtrpSlOAZQ7HaaIFuOYbgqgUM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -184,6 +188,7 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -197,6 +202,7 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.0.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -230,6 +236,7 @@ github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imkira/go-interpol v1.0.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U= github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -256,14 +263,17 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -337,7 +347,9 @@ github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXW github.com/olivere/elastic/v7 v7.0.15 h1:v7kX5S+oMFfYKS4ZyzD37GH6lfZSpBo9atynRwBUywE= github.com/olivere/elastic/v7 v7.0.15/go.mod h1:+FgncZ8ho1QF3NlBo77XbuoTKYHhvEOfFZKIAfHnnDE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= @@ -373,6 +385,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY= github.com/scryner/lfreequeue v0.0.0-20121212074822-473f33702129/go.mod h1:0OrdloYlIayHGsgKYlwEnmdrPWmuYtbdS6Dm71PprFM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= @@ -437,14 +450,24 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fastrand v1.0.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -510,6 +533,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -681,4 +705,5 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e/go.mod h1:nejbQVfXh96n9dSF6cH3Jsk/QI1Z2oEL7sSI2ifXFNA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/backend/main.go b/backend/main.go index 33c1d00d..c514dc67 100644 --- a/backend/main.go +++ b/backend/main.go @@ -1,9 +1,9 @@ package main -import "crawlab/services" +import "crawlab/apps" func main() { - api := services.NewApiService() + api := apps.NewApi() api.Init() api.Run() From 6bfbd90d8d8eda1157a14c3691e9d6afb70df1d3 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Thu, 8 Apr 2021 13:21:04 +0800 Subject: [PATCH 06/19] renaming --- backend/apps/api.go | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/backend/apps/api.go b/backend/apps/api.go index 5fbd67e7..67e86ba1 100644 --- a/backend/apps/api.go +++ b/backend/apps/api.go @@ -5,7 +5,9 @@ import ( "fmt" "github.com/apex/log" "github.com/crawlab-team/crawlab-core/config" + "github.com/crawlab-team/crawlab-core/controllers" "github.com/crawlab-team/crawlab-core/middlewares" + "github.com/crawlab-team/crawlab-core/models" "github.com/crawlab-team/crawlab-core/routes" "github.com/crawlab-team/crawlab-db/mongo" "github.com/crawlab-team/crawlab-db/redis" @@ -24,29 +26,35 @@ type Api struct { app *gin.Engine } -func (svc *Api) Init() { +func (app *Api) Init() { // initialize config - _ = svc.initService("config", config.InitConfig) + _ = app.initModule("config", config.InitConfig) // initialize mongo - _ = svc.initService("mongo", mongo.InitMongo) + _ = app.initModule("mongo", mongo.InitMongo) // initialize redis - _ = svc.initService("redis", redis.InitRedis) + _ = app.initModule("redis", redis.InitRedis) + + // initialize model services + _ = app.initModule("modeServices", models.InitModelServices) + + // initialize controllers + _ = app.initModule("controllers", controllers.InitControllers) // initialize middlewares - _ = svc.initServiceWithApp("middlewares", middlewares.InitMiddlewares) + _ = app.initModuleWithApp("middlewares", middlewares.InitMiddlewares) // initialize routes - _ = svc.initServiceWithApp("routes", routes.InitRoutes) + _ = app.initModuleWithApp("routes", routes.InitRoutes) } -func (svc *Api) Run() { +func (app *Api) Run() { host := viper.GetString("server.host") port := viper.GetString("server.port") address := net.JoinHostPort(host, port) srv := &http.Server{ - Handler: svc.app, + Handler: app.app, Addr: address, } go func() { @@ -68,13 +76,13 @@ func (svc *Api) Run() { } } -func (svc *Api) initServiceWithApp(name string, fn func(app *gin.Engine) error) (err error) { - return svc.initService(name, func() error { - return fn(svc.app) +func (app *Api) initModuleWithApp(name string, fn func(app *gin.Engine) error) (err error) { + return app.initModule(name, func() error { + return fn(app.app) }) } -func (svc *Api) initService(name string, fn func() error) (err error) { +func (app *Api) initModule(name string, fn func() error) (err error) { if err := fn(); err != nil { log.Error(fmt.Sprintf("init %s error: %s", name, err.Error())) _ = trace.TraceError(err) From 941b2316c35f8126b6f701d4788dd8e8d82c4a22 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Tue, 20 Apr 2021 13:20:51 +0800 Subject: [PATCH 07/19] fixed namings --- .gitmodules | 15 +++++++++++++++ backend/apps/api.go | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..151cc946 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "backend/core"] + path = backend/core + url = https://github.com/crawlab-team/crawlab-core +[submodule "backend/db"] + path = backend/db + url = https://github.com/crawlab-team/crawlab-db +[submodule "backend/fs"] + path = backend/fs + url = https://github.com/crawlab-team/crawlab-fs +[submodule "backend/vcs"] + path = backend/vcs + url = https://github.com/crawlab-team/crawlab-vcs +[submodule "backend/log"] + path = backend/log + url = https://github.com/crawlab-team/crawlab-log diff --git a/backend/apps/api.go b/backend/apps/api.go index 67e86ba1..11b1b2b2 100644 --- a/backend/apps/api.go +++ b/backend/apps/api.go @@ -37,7 +37,7 @@ func (app *Api) Init() { _ = app.initModule("redis", redis.InitRedis) // initialize model services - _ = app.initModule("modeServices", models.InitModelServices) + _ = app.initModule("mode-services", models.InitModelServices) // initialize controllers _ = app.initModule("controllers", controllers.InitControllers) From 1c0aba161c40a4af036a9738bac877317b91b926 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Tue, 27 Apr 2021 11:34:12 +0800 Subject: [PATCH 08/19] added cli --- backend/apps/api.go | 13 +-- backend/apps/base.go | 27 +++++ backend/apps/handler.go | 21 ++++ backend/cmd/api.go | 21 ++++ backend/cmd/handler.go | 21 ++++ backend/cmd/root.go | 60 ++++++++++ backend/go.mod | 4 +- backend/go.sum | 76 +++++++----- backend/main.go | 251 +-------------------------------------- backend/main_legacy.go | 252 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 453 insertions(+), 293 deletions(-) create mode 100644 backend/apps/handler.go create mode 100644 backend/cmd/api.go create mode 100644 backend/cmd/handler.go create mode 100644 backend/cmd/root.go create mode 100644 backend/main_legacy.go diff --git a/backend/apps/api.go b/backend/apps/api.go index 11b1b2b2..f9f7eacd 100644 --- a/backend/apps/api.go +++ b/backend/apps/api.go @@ -2,7 +2,6 @@ package apps import ( "context" - "fmt" "github.com/apex/log" "github.com/crawlab-team/crawlab-core/config" "github.com/crawlab-team/crawlab-core/controllers" @@ -11,7 +10,6 @@ import ( "github.com/crawlab-team/crawlab-core/routes" "github.com/crawlab-team/crawlab-db/mongo" "github.com/crawlab-team/crawlab-db/redis" - "github.com/crawlab-team/go-trace" "github.com/gin-gonic/gin" "github.com/spf13/viper" "net" @@ -23,6 +21,7 @@ import ( ) type Api struct { + BaseApp app *gin.Engine } @@ -82,16 +81,6 @@ func (app *Api) initModuleWithApp(name string, fn func(app *gin.Engine) error) ( }) } -func (app *Api) initModule(name string, fn func() error) (err error) { - if err := fn(); err != nil { - log.Error(fmt.Sprintf("init %s error: %s", name, err.Error())) - _ = trace.TraceError(err) - panic(err) - } - log.Info(fmt.Sprintf("initialized %s successfully", name)) - return nil -} - func NewApi() *Api { app := gin.New() return &Api{ diff --git a/backend/apps/base.go b/backend/apps/base.go index 2eb759f4..b07ee94f 100644 --- a/backend/apps/base.go +++ b/backend/apps/base.go @@ -1,6 +1,33 @@ package apps +import ( + "fmt" + "github.com/apex/log" + "github.com/crawlab-team/go-trace" +) + type App interface { Init() Run() } + +type BaseApp struct { +} + +func (app *BaseApp) Init() { + panic("implement me") +} + +func (app *BaseApp) Run() { + panic("implement me") +} + +func (app *BaseApp) initModule(name string, fn func() error) (err error) { + if err := fn(); err != nil { + log.Error(fmt.Sprintf("init %s error: %s", name, err.Error())) + _ = trace.TraceError(err) + panic(err) + } + log.Info(fmt.Sprintf("initialized %s successfully", name)) + return nil +} diff --git a/backend/apps/handler.go b/backend/apps/handler.go new file mode 100644 index 00000000..dacb32c4 --- /dev/null +++ b/backend/apps/handler.go @@ -0,0 +1,21 @@ +package apps + +import ( + "github.com/crawlab-team/crawlab-core/services" +) + +type Handler struct { + BaseApp +} + +func (app *Handler) Init() { + _ = app.initModule("task-service", services.InitTaskService) +} + +func (app *Handler) Run() { + panic("implement me") +} + +func NewHandler() *Handler { + return &Handler{} +} diff --git a/backend/cmd/api.go b/backend/cmd/api.go new file mode 100644 index 00000000..fd265273 --- /dev/null +++ b/backend/cmd/api.go @@ -0,0 +1,21 @@ +package cmd + +import ( + "crawlab/apps" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(apiCmd) +} + +var apiCmd = &cobra.Command{ + Use: "api", + Short: "Start API server", + Long: `Start API server of Crawlab which serves data to frontend`, + Run: func(cmd *cobra.Command, args []string) { + api := apps.NewApi() + api.Init() + api.Run() + }, +} diff --git a/backend/cmd/handler.go b/backend/cmd/handler.go new file mode 100644 index 00000000..747880a6 --- /dev/null +++ b/backend/cmd/handler.go @@ -0,0 +1,21 @@ +package cmd + +import ( + "crawlab/apps" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(handlerCmd) +} + +var handlerCmd = &cobra.Command{ + Use: "handler", + Short: "Start API server", + Long: `Start API server of Crawlab which serves data to frontend`, + Run: func(cmd *cobra.Command, args []string) { + handler := apps.NewHandler() + handler.Init() + handler.Run() + }, +} diff --git a/backend/cmd/root.go b/backend/cmd/root.go new file mode 100644 index 00000000..6b2eb743 --- /dev/null +++ b/backend/cmd/root.go @@ -0,0 +1,60 @@ +package cmd + +import ( + "fmt" + + "github.com/mitchellh/go-homedir" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + // Used for flags. + cfgFile string + + rootCmd = &cobra.Command{ + Use: "crawlab", + Short: "CLI tool for Crawlab", + Long: `The CLI tool is for controlling against Crawlab. +Crawlab is a distributed web crawler and task admin platform +aimed at making web crawling and task management easier. +`, + } +) + +// Execute executes the root command. +func Execute() error { + return rootCmd.Execute() +} + +func init() { + cobra.OnInitialize(initConfig) + + //rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") + //rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") + //rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") + //rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") + //viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) + //viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) +} + +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := homedir.Dir() + cobra.CheckErr(err) + + // Search config in home directory with name ".cobra" (without extension). + viper.AddConfigPath(home) + viper.SetConfigName(".cobra") + } + + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err == nil { + fmt.Println("Using config file:", viper.ConfigFileUsed()) + } +} diff --git a/backend/go.mod b/backend/go.mod index f70efcd7..64e7f858 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -19,7 +19,7 @@ require ( github.com/crawlab-team/crawlab-db v0.0.2 github.com/crawlab-team/go-trace v0.0.0 github.com/gin-gonic/gin v1.6.3 - github.com/go-playground/validator/v10 v10.3.0 - github.com/olivere/elastic/v7 v7.0.15 + github.com/mitchellh/go-homedir v1.1.0 + github.com/spf13/cobra v1.1.3 github.com/spf13/viper v1.7.1 ) diff --git a/backend/go.sum b/backend/go.sum index 776c8761..236692df 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -19,9 +19,9 @@ github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Masterminds/sprig v2.16.0+incompatible h1:QZbMUPxRQ50EKAq3LFMnxddMu88/EUUG3qmxwtDmPsY= github.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd h1:+CYOsXi89xOqBkj7CuEJjA2It+j+R3ngUZEydr6mtkw= -github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= @@ -63,9 +63,7 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/crawlab-team/crawlab-fs v0.0.0 h1:RGPWKB7ORgGEYLS5uplS/dIbdY8ktKmfBHM2MxxwQKQ= -github.com/crawlab-team/crawlab-fs v0.0.0/go.mod h1:k2VXprQspLAmbgO5sSpqMjg/xP4iKDkW4RyTWY8eTZM= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -79,8 +77,10 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fasthttp/websocket v1.4.2 h1:AU/zSiIIAuJjBMf5o+vO0syGOnEfvZRu40xIhW/3RuM= github.com/fasthttp/websocket v1.4.2/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.0.0 h1:BrX964Rv5uQ3wwS+KRUAJCBBw5PQmgJfJ6v4yly5QwU= github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= @@ -90,6 +90,7 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gavv/httpexpect/v2 v2.2.0 h1:0VwaEBmQaNFHX9x591A8Up+8shCwdF/nF0qlRd/nI48= github.com/gavv/httpexpect/v2 v2.2.0/go.mod h1:lnd0TqJLrP+wkJk3SFwtrpSlOAZQ7HaaIFuOYbgqgUM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -98,12 +99,11 @@ github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI= github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= @@ -111,6 +111,7 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -187,7 +188,9 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -203,6 +206,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.0.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -229,16 +233,17 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imkira/go-interpol v1.0.0 h1:HrmLyvOLJyjR0YofMw8QGdCIuYOs4TJUBDNU5sJC09E= github.com/imkira/go-interpol v1.0.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U= github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ= github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= @@ -249,6 +254,7 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= @@ -263,6 +269,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= @@ -282,17 +289,15 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/linxGnu/goseaweedfs v0.1.5 h1:7dChPdq8+fsPH0yqxKEofPhiosaar4LWePm4M+1Taz0= -github.com/linxGnu/goseaweedfs v0.1.5/go.mod h1:Zwe/7H7FJaPQyMTNKXgv6fhVDw6qi34MMJQp1K0VLNc= github.com/linxGnu/gumble v1.0.0 h1:OAJud8Hy4rmV9I5p/KTRiVpwwklMTd9Ankza3Mz7a4M= github.com/linxGnu/gumble v1.0.0/go.mod h1:iyhNJpBHvJ0q2Hr41iiZRJyj6LLF47i2a9C9zLiucVY= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k= @@ -307,6 +312,7 @@ github.com/matcornic/hermes v1.2.0 h1:AuqZpYcTOtTB7cahdevLfnhIpfzmpqw5Czv8vpdnFD github.com/matcornic/hermes v1.2.0/go.mod h1:lujJomb016Xjv8wBnWlNvUdtmvowjjfkqri5J/+1hYc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -340,6 +346,7 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88= @@ -347,12 +354,13 @@ github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXW github.com/olivere/elastic/v7 v7.0.15 h1:v7kX5S+oMFfYKS4ZyzD37GH6lfZSpBo9atynRwBUywE= github.com/olivere/elastic/v7 v7.0.15/go.mod h1:+FgncZ8ho1QF3NlBo77XbuoTKYHhvEOfFZKIAfHnnDE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= @@ -382,9 +390,11 @@ github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY= github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY= github.com/scryner/lfreequeue v0.0.0-20121212074822-473f33702129/go.mod h1:0OrdloYlIayHGsgKYlwEnmdrPWmuYtbdS6Dm71PprFM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -414,19 +424,21 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -437,6 +449,7 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= @@ -450,7 +463,9 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.9.0 h1:hNpmUdy/+ZXYpGy0OBfm7K0UQTzb73W0T0U4iJIVrMw= github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fastrand v1.0.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= @@ -460,13 +475,20 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg= github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= @@ -492,8 +514,6 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -531,8 +551,6 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -571,14 +589,10 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg= golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -611,8 +625,6 @@ golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a h1:mEQZbbaBjWyLNy0tmZmgEuQAR8XOQ3hL8GYi3J/NG64= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -669,8 +681,10 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= @@ -679,12 +693,7 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/russross/blackfriday.v2 v2.0.0 h1:+FlnIV8DSQnT7NZ43hcVKcdJdzZoeCmJj4Ql8gq5keA= gopkg.in/russross/blackfriday.v2 v2.0.0/go.mod h1:6sSBNz/GtOm/pJTuh5UmBK2ZHfmnxGbl2NZg1UliSOI= -gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= @@ -697,6 +706,8 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -705,5 +716,6 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e h1:C7q+e9M5nggAvWfVg9Nl66kebKeuJlP3FD58V4RR5wo= moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e/go.mod h1:nejbQVfXh96n9dSF6cH3Jsk/QI1Z2oEL7sSI2ifXFNA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/backend/main.go b/backend/main.go index c514dc67..2c48caa1 100644 --- a/backend/main.go +++ b/backend/main.go @@ -1,252 +1,9 @@ package main -import "crawlab/apps" +import ( + "crawlab/cmd" +) func main() { - api := apps.NewApi() - api.Init() - api.Run() - - //if model.IsMaster() { - // // 初始化定时任务 - // if err := services.InitScheduler(); err != nil { - // log.Error("init scheduler error:" + err.Error()) - // debug.PrintStack() - // panic(err) - // } - // log.Info("initialized schedule successfully") - // - // // 初始化用户服务 - // if err := services.InitUserService(); err != nil { - // log.Error("init user service error:" + err.Error()) - // debug.PrintStack() - // panic(err) - // } - // log.Info("initialized user service successfully") - // - // // 初始化依赖服务 - // if err := services.InitDepsFetcher(); err != nil { - // log.Error("init dependency fetcher error:" + err.Error()) - // debug.PrintStack() - // panic(err) - // } - // log.Info("initialized dependency fetcher successfully") - // - // // 初始化清理服务 - // if err := services.InitCleanService(); err != nil { - // log.Error("init clean service error:" + err.Error()) - // debug.PrintStack() - // panic(err) - // } - // log.Info("initialized clean service successfully") - //} - // - //// 初始化任务执行器 - //if err := services.InitTaskExecutor(); err != nil { - // log.Error("init task executor error:" + err.Error()) - // debug.PrintStack() - // panic(err) - //} - //log.Info("initialized task executor successfully") - // - //// 初始化爬虫服务 - //if err := services.InitSpiderService(); err != nil { - // log.Error("init spider service error:" + err.Error()) - // debug.PrintStack() - // panic(err) - //} - //log.Info("initialized spider service successfully") - // - //// 初始化RPC服务 - //if err := rpc.InitRpcService(); err != nil { - // log.Error("init rpc service error:" + err.Error()) - // debug.PrintStack() - // panic(err) - //} - //log.Info("initialized rpc service successfully") - - // 以下为主节点服务 - //if model.IsMaster() { - // // 中间件 - // esClientStr := viper.GetString("setting.esClient") - // if viper.GetString("setting.crawlabLogToES") == "Y" && esClientStr != "" { - // ctx := context.Background() - // esClient, err := elastic.NewClient(elastic.SetURL(esClientStr), elastic.SetSniff(false)) - // if err != nil { - // log.Error("Init es client Error:" + err.Error()) - // } - // app.Use(middlewares.EsLog(ctx, esClient)) - // } - // app.Use(middlewares.CORSMiddleware()) - // anonymousGroup := app.Group("/") - // { - // anonymousGroup.POST("/login", routes.Login) // 用户登录 - // anonymousGroup.PUT("/users", routes.PutUser) // 添加用户 - // anonymousGroup.GET("/setting", routes.GetSetting) // 获取配置信息 - // // release版本 - // anonymousGroup.GET("/version", routes.GetVersion) // 获取发布的版本 - // anonymousGroup.GET("/releases/latest", routes.GetLatestRelease) // 获取最近发布的版本 - // // 文档 - // anonymousGroup.GET("/docs", routes.GetDocs) // 获取文档数据 - // } - // authGroup := app.Group("/", middlewares.AuthorizationMiddleware()) - // { - // // 节点 - // { - // authGroup.GET("/nodes", routes.GetNodeList) // 节点列表 - // authGroup.GET("/nodes/:id", routes.GetNode) // 节点详情 - // authGroup.POST("/nodes/:id", routes.PostNode) // 修改节点 - // authGroup.GET("/nodes/:id/tasks", routes.GetNodeTaskList) // 节点任务列表 - // authGroup.GET("/nodes/:id/system", routes.GetSystemInfo) // 节点任务列表 - // authGroup.DELETE("/nodes/:id", routes.DeleteNode) // 删除节点 - // authGroup.GET("/nodes/:id/langs", routes.GetLangList) // 节点语言环境列表 - // authGroup.GET("/nodes/:id/deps", routes.GetDepList) // 节点第三方依赖列表 - // authGroup.GET("/nodes/:id/deps/installed", routes.GetInstalledDepList) // 节点已安装第三方依赖列表 - // authGroup.POST("/nodes/:id/deps/install", routes.InstallDep) // 节点安装依赖 - // authGroup.POST("/nodes/:id/deps/uninstall", routes.UninstallDep) // 节点卸载依赖 - // authGroup.POST("/nodes/:id/langs/install", routes.InstallLang) // 节点安装语言 - // } - // // 爬虫 - // { - // authGroup.GET("/spiders", routes.GetSpiderList) // 爬虫列表 - // authGroup.GET("/spiders/:id", routes.GetSpider) // 爬虫详情 - // authGroup.PUT("/spiders", routes.PutSpider) // 添加爬虫 - // authGroup.POST("/spiders", routes.UploadSpider) // 上传爬虫 - // authGroup.POST("/spiders/:id", routes.PostSpider) // 修改爬虫 - // authGroup.POST("/spiders/:id/publish", routes.PublishSpider) // 发布爬虫 - // authGroup.POST("/spiders/:id/upload", routes.UploadSpiderFromId) // 上传爬虫(ID) - // authGroup.DELETE("/spiders", routes.DeleteSelectedSpider) // 删除选择的爬虫 - // authGroup.DELETE("/spiders/:id", routes.DeleteSpider) // 删除爬虫 - // authGroup.POST("/spiders/:id/copy", routes.CopySpider) // 拷贝爬虫 - // authGroup.GET("/spiders/:id/tasks", routes.GetSpiderTasks) // 爬虫任务列表 - // authGroup.GET("/spiders/:id/file/tree", routes.GetSpiderFileTree) // 爬虫文件目录树读取 - // authGroup.GET("/spiders/:id/file", routes.GetSpiderFile) // 爬虫文件读取 - // authGroup.POST("/spiders/:id/file", routes.PostSpiderFile) // 爬虫文件更改 - // authGroup.PUT("/spiders/:id/file", routes.PutSpiderFile) // 爬虫文件创建 - // authGroup.PUT("/spiders/:id/dir", routes.PutSpiderDir) // 爬虫目录创建 - // authGroup.DELETE("/spiders/:id/file", routes.DeleteSpiderFile) // 爬虫文件删除 - // authGroup.POST("/spiders/:id/file/rename", routes.RenameSpiderFile) // 爬虫文件重命名 - // authGroup.GET("/spiders/:id/dir", routes.GetSpiderDir) // 爬虫目录 - // authGroup.GET("/spiders/:id/stats", routes.GetSpiderStats) // 爬虫统计数据 - // authGroup.GET("/spiders/:id/schedules", routes.GetSpiderSchedules) // 爬虫定时任务 - // authGroup.GET("/spiders/:id/scrapy/spiders", routes.GetSpiderScrapySpiders) // Scrapy 爬虫名称列表 - // authGroup.PUT("/spiders/:id/scrapy/spiders", routes.PutSpiderScrapySpiders) // Scrapy 爬虫创建爬虫 - // authGroup.GET("/spiders/:id/scrapy/settings", routes.GetSpiderScrapySettings) // Scrapy 爬虫设置 - // authGroup.POST("/spiders/:id/scrapy/settings", routes.PostSpiderScrapySettings) // Scrapy 爬虫修改设置 - // authGroup.GET("/spiders/:id/scrapy/items", routes.GetSpiderScrapyItems) // Scrapy 爬虫 items - // authGroup.POST("/spiders/:id/scrapy/items", routes.PostSpiderScrapyItems) // Scrapy 爬虫修改 items - // authGroup.GET("/spiders/:id/scrapy/pipelines", routes.GetSpiderScrapyPipelines) // Scrapy 爬虫 pipelines - // authGroup.GET("/spiders/:id/scrapy/spider/filepath", routes.GetSpiderScrapySpiderFilepath) // Scrapy 爬虫 pipelines - // authGroup.POST("/spiders/:id/git/sync", routes.PostSpiderSyncGit) // 爬虫 Git 同步 - // authGroup.POST("/spiders/:id/git/reset", routes.PostSpiderResetGit) // 爬虫 Git 重置 - // authGroup.POST("/spiders-cancel", routes.CancelSelectedSpider) // 停止所选爬虫任务 - // authGroup.POST("/spiders-run", routes.RunSelectedSpider) // 运行所选爬虫 - // authGroup.POST("/spiders-set-projects", routes.SetProjectsSelectedSpider) // 批量设置爬虫项目 - // } - // // 可配置爬虫 - // { - // authGroup.GET("/config_spiders/:id/config", routes.GetConfigSpiderConfig) // 获取可配置爬虫配置 - // authGroup.POST("/config_spiders/:id/config", routes.PostConfigSpiderConfig) // 更改可配置爬虫配置 - // authGroup.PUT("/config_spiders", routes.PutConfigSpider) // 添加可配置爬虫 - // authGroup.POST("/config_spiders/:id", routes.PostConfigSpider) // 修改可配置爬虫 - // authGroup.POST("/config_spiders/:id/upload", routes.UploadConfigSpider) // 上传可配置爬虫 - // authGroup.POST("/config_spiders/:id/spiderfile", routes.PostConfigSpiderSpiderfile) // 上传可配置爬虫 - // authGroup.GET("/config_spiders_templates", routes.GetConfigSpiderTemplateList) // 获取可配置爬虫模版列表 - // } - // // 任务 - // { - // authGroup.GET("/tasks", routes.GetTaskList) // 任务列表 - // authGroup.GET("/tasks/:id", routes.GetTask) // 任务详情 - // authGroup.PUT("/tasks", routes.PutTask) // 派发任务 - // authGroup.PUT("/tasks/batch", routes.PutBatchTasks) // 批量派发任务 - // authGroup.DELETE("/tasks/:id", routes.DeleteTask) // 删除任务 - // authGroup.DELETE("/tasks", routes.DeleteSelectedTask) // 删除多个任务 - // //authGroup.DELETE("/tasks_by_status", routes.DeleteTaskByStatus) // 删除指定状态的任务 - // authGroup.POST("/tasks/:id/cancel", routes.CancelTask) // 取消任务 - // authGroup.GET("/tasks/:id/log", routes.GetTaskLog) // 任务日志 - // authGroup.GET("/tasks/:id/error-log", routes.GetTaskErrorLog) // 任务错误日志 - // authGroup.GET("/tasks/:id/results", routes.GetTaskResults) // 任务结果 - // authGroup.GET("/tasks/:id/results/download", routes.DownloadTaskResultsCsv) // 下载任务结果 - // authGroup.POST("/tasks/:id/restart", routes.RestartTask) // 重新开始任务 - // authGroup.POST("/tasks-cancel", routes.CancelSelectedTask) // 批量取消任务 - // authGroup.POST("/tasks-restart", routes.RestartSelectedTask) // 批量重试任务 - // } - // // 系统任务/脚本 - // { - // authGroup.PUT("/system-tasks", routes.PutSystemTask) // 运行系统任务 - // authGroup.GET("/system-scripts", routes.GetSystemScripts) // 获取系统脚本列表 - // } - // // 定时任务 - // { - // authGroup.GET("/schedules", routes.GetScheduleList) // 定时任务列表 - // authGroup.GET("/schedules/:id", routes.GetSchedule) // 定时任务详情 - // authGroup.PUT("/schedules", routes.PutSchedule) // 创建定时任务 - // authGroup.PUT("/schedules/batch", routes.PutBatchSchedules) // 批量创建定时任务 - // authGroup.POST("/schedules/:id", routes.PostSchedule) // 修改定时任务 - // authGroup.DELETE("/schedules/:id", routes.DeleteSchedule) // 删除定时任务 - // authGroup.DELETE("/schedules", routes.DeleteBatchSchedules) // 批量删除定时任务 - // authGroup.POST("/schedules/:id/disable", routes.DisableSchedule) // 禁用定时任务 - // authGroup.POST("/schedules/:id/enable", routes.EnableSchedule) // 启用定时任务 - // authGroup.POST("/schedules-set-enabled", routes.SetEnabledSchedules) // 批量设置定时任务状态 - // } - // // 用户 - // { - // authGroup.GET("/users", routes.GetUserList) // 用户列表 - // authGroup.GET("/users/:id", routes.GetUser) // 用户详情 - // authGroup.POST("/users/:id", routes.PostUser) // 更改用户 - // authGroup.DELETE("/users/:id", routes.DeleteUser) // 删除用户 - // authGroup.PUT("/users-add", routes.PutUser) // 添加用户 - // authGroup.GET("/me", routes.GetMe) // 获取自己账户 - // authGroup.POST("/me", routes.PostMe) // 修改自己账户 - // authGroup.POST("/me/change-password", routes.PostMeChangePassword) // 修改自己密码 - // } - // // 系统 - // { - // authGroup.GET("/system/deps/:lang", routes.GetAllDepList) // 节点所有第三方依赖列表 - // authGroup.GET("/system/deps/:lang/:dep_name/json", routes.GetDepJson) // 节点第三方依赖JSON - // } - // // 全局变量 - // { - // authGroup.GET("/variables", routes.GetVariableList) // 列表 - // authGroup.PUT("/variable", routes.PutVariable) // 新增 - // authGroup.POST("/variable/:id", routes.PostVariable) // 修改 - // authGroup.DELETE("/variable/:id", routes.DeleteVariable) // 删除 - // } - // // 项目 - // { - // authGroup.GET("/projects", routes.GetProjectList) // 列表 - // authGroup.GET("/projects/tags", routes.GetProjectTags) // 项目标签 - // authGroup.PUT("/projects", routes.PutProject) // 修改 - // authGroup.POST("/projects/:id", routes.PostProject) // 新增 - // authGroup.DELETE("/projects/:id", routes.DeleteProject) // 删除 - // } - // // 操作 - // { - // //authGroup.GET("/actions", routes.GetActionList) // 操作列表 - // //authGroup.GET("/actions/:id", routes.GetAction) // 操作 - // authGroup.PUT("/actions", routes.PutAction) // 新增操作 - // //authGroup.POST("/actions/:id", routes.PostAction) // 修改操作 - // } - // // API Token - // { - // authGroup.GET("/tokens", routes.GetTokens) // 获取 Tokens - // authGroup.PUT("/tokens", routes.PutToken) // 添加 Token - // authGroup.DELETE("/tokens/:id", routes.DeleteToken) // 删除 Token - // } - // // 统计数据 - // authGroup.GET("/stats/home", routes.GetHomeStats) // 首页统计数据 - // // 文件 - // authGroup.GET("/file", routes.GetFile) // 获取文件 - // // Git - // authGroup.GET("/git/branches", routes.GetGitRemoteBranches) // 获取 Git 分支 - // authGroup.GET("/git/public-key", routes.GetGitSshPublicKey) // 获取 SSH 公钥 - // authGroup.GET("/git/commits", routes.GetGitCommits) // 获取 Git Commits - // authGroup.POST("/git/checkout", routes.PostGitCheckout) // 获取 Git Commits - // } - //} - - // 路由ping - //app.GET("/ping", routes.Ping) - - // 运行服务器 + _ = cmd.Execute() } diff --git a/backend/main_legacy.go b/backend/main_legacy.go new file mode 100644 index 00000000..c514dc67 --- /dev/null +++ b/backend/main_legacy.go @@ -0,0 +1,252 @@ +package main + +import "crawlab/apps" + +func main() { + api := apps.NewApi() + api.Init() + api.Run() + + //if model.IsMaster() { + // // 初始化定时任务 + // if err := services.InitScheduler(); err != nil { + // log.Error("init scheduler error:" + err.Error()) + // debug.PrintStack() + // panic(err) + // } + // log.Info("initialized schedule successfully") + // + // // 初始化用户服务 + // if err := services.InitUserService(); err != nil { + // log.Error("init user service error:" + err.Error()) + // debug.PrintStack() + // panic(err) + // } + // log.Info("initialized user service successfully") + // + // // 初始化依赖服务 + // if err := services.InitDepsFetcher(); err != nil { + // log.Error("init dependency fetcher error:" + err.Error()) + // debug.PrintStack() + // panic(err) + // } + // log.Info("initialized dependency fetcher successfully") + // + // // 初始化清理服务 + // if err := services.InitCleanService(); err != nil { + // log.Error("init clean service error:" + err.Error()) + // debug.PrintStack() + // panic(err) + // } + // log.Info("initialized clean service successfully") + //} + // + //// 初始化任务执行器 + //if err := services.InitTaskExecutor(); err != nil { + // log.Error("init task executor error:" + err.Error()) + // debug.PrintStack() + // panic(err) + //} + //log.Info("initialized task executor successfully") + // + //// 初始化爬虫服务 + //if err := services.InitSpiderService(); err != nil { + // log.Error("init spider service error:" + err.Error()) + // debug.PrintStack() + // panic(err) + //} + //log.Info("initialized spider service successfully") + // + //// 初始化RPC服务 + //if err := rpc.InitRpcService(); err != nil { + // log.Error("init rpc service error:" + err.Error()) + // debug.PrintStack() + // panic(err) + //} + //log.Info("initialized rpc service successfully") + + // 以下为主节点服务 + //if model.IsMaster() { + // // 中间件 + // esClientStr := viper.GetString("setting.esClient") + // if viper.GetString("setting.crawlabLogToES") == "Y" && esClientStr != "" { + // ctx := context.Background() + // esClient, err := elastic.NewClient(elastic.SetURL(esClientStr), elastic.SetSniff(false)) + // if err != nil { + // log.Error("Init es client Error:" + err.Error()) + // } + // app.Use(middlewares.EsLog(ctx, esClient)) + // } + // app.Use(middlewares.CORSMiddleware()) + // anonymousGroup := app.Group("/") + // { + // anonymousGroup.POST("/login", routes.Login) // 用户登录 + // anonymousGroup.PUT("/users", routes.PutUser) // 添加用户 + // anonymousGroup.GET("/setting", routes.GetSetting) // 获取配置信息 + // // release版本 + // anonymousGroup.GET("/version", routes.GetVersion) // 获取发布的版本 + // anonymousGroup.GET("/releases/latest", routes.GetLatestRelease) // 获取最近发布的版本 + // // 文档 + // anonymousGroup.GET("/docs", routes.GetDocs) // 获取文档数据 + // } + // authGroup := app.Group("/", middlewares.AuthorizationMiddleware()) + // { + // // 节点 + // { + // authGroup.GET("/nodes", routes.GetNodeList) // 节点列表 + // authGroup.GET("/nodes/:id", routes.GetNode) // 节点详情 + // authGroup.POST("/nodes/:id", routes.PostNode) // 修改节点 + // authGroup.GET("/nodes/:id/tasks", routes.GetNodeTaskList) // 节点任务列表 + // authGroup.GET("/nodes/:id/system", routes.GetSystemInfo) // 节点任务列表 + // authGroup.DELETE("/nodes/:id", routes.DeleteNode) // 删除节点 + // authGroup.GET("/nodes/:id/langs", routes.GetLangList) // 节点语言环境列表 + // authGroup.GET("/nodes/:id/deps", routes.GetDepList) // 节点第三方依赖列表 + // authGroup.GET("/nodes/:id/deps/installed", routes.GetInstalledDepList) // 节点已安装第三方依赖列表 + // authGroup.POST("/nodes/:id/deps/install", routes.InstallDep) // 节点安装依赖 + // authGroup.POST("/nodes/:id/deps/uninstall", routes.UninstallDep) // 节点卸载依赖 + // authGroup.POST("/nodes/:id/langs/install", routes.InstallLang) // 节点安装语言 + // } + // // 爬虫 + // { + // authGroup.GET("/spiders", routes.GetSpiderList) // 爬虫列表 + // authGroup.GET("/spiders/:id", routes.GetSpider) // 爬虫详情 + // authGroup.PUT("/spiders", routes.PutSpider) // 添加爬虫 + // authGroup.POST("/spiders", routes.UploadSpider) // 上传爬虫 + // authGroup.POST("/spiders/:id", routes.PostSpider) // 修改爬虫 + // authGroup.POST("/spiders/:id/publish", routes.PublishSpider) // 发布爬虫 + // authGroup.POST("/spiders/:id/upload", routes.UploadSpiderFromId) // 上传爬虫(ID) + // authGroup.DELETE("/spiders", routes.DeleteSelectedSpider) // 删除选择的爬虫 + // authGroup.DELETE("/spiders/:id", routes.DeleteSpider) // 删除爬虫 + // authGroup.POST("/spiders/:id/copy", routes.CopySpider) // 拷贝爬虫 + // authGroup.GET("/spiders/:id/tasks", routes.GetSpiderTasks) // 爬虫任务列表 + // authGroup.GET("/spiders/:id/file/tree", routes.GetSpiderFileTree) // 爬虫文件目录树读取 + // authGroup.GET("/spiders/:id/file", routes.GetSpiderFile) // 爬虫文件读取 + // authGroup.POST("/spiders/:id/file", routes.PostSpiderFile) // 爬虫文件更改 + // authGroup.PUT("/spiders/:id/file", routes.PutSpiderFile) // 爬虫文件创建 + // authGroup.PUT("/spiders/:id/dir", routes.PutSpiderDir) // 爬虫目录创建 + // authGroup.DELETE("/spiders/:id/file", routes.DeleteSpiderFile) // 爬虫文件删除 + // authGroup.POST("/spiders/:id/file/rename", routes.RenameSpiderFile) // 爬虫文件重命名 + // authGroup.GET("/spiders/:id/dir", routes.GetSpiderDir) // 爬虫目录 + // authGroup.GET("/spiders/:id/stats", routes.GetSpiderStats) // 爬虫统计数据 + // authGroup.GET("/spiders/:id/schedules", routes.GetSpiderSchedules) // 爬虫定时任务 + // authGroup.GET("/spiders/:id/scrapy/spiders", routes.GetSpiderScrapySpiders) // Scrapy 爬虫名称列表 + // authGroup.PUT("/spiders/:id/scrapy/spiders", routes.PutSpiderScrapySpiders) // Scrapy 爬虫创建爬虫 + // authGroup.GET("/spiders/:id/scrapy/settings", routes.GetSpiderScrapySettings) // Scrapy 爬虫设置 + // authGroup.POST("/spiders/:id/scrapy/settings", routes.PostSpiderScrapySettings) // Scrapy 爬虫修改设置 + // authGroup.GET("/spiders/:id/scrapy/items", routes.GetSpiderScrapyItems) // Scrapy 爬虫 items + // authGroup.POST("/spiders/:id/scrapy/items", routes.PostSpiderScrapyItems) // Scrapy 爬虫修改 items + // authGroup.GET("/spiders/:id/scrapy/pipelines", routes.GetSpiderScrapyPipelines) // Scrapy 爬虫 pipelines + // authGroup.GET("/spiders/:id/scrapy/spider/filepath", routes.GetSpiderScrapySpiderFilepath) // Scrapy 爬虫 pipelines + // authGroup.POST("/spiders/:id/git/sync", routes.PostSpiderSyncGit) // 爬虫 Git 同步 + // authGroup.POST("/spiders/:id/git/reset", routes.PostSpiderResetGit) // 爬虫 Git 重置 + // authGroup.POST("/spiders-cancel", routes.CancelSelectedSpider) // 停止所选爬虫任务 + // authGroup.POST("/spiders-run", routes.RunSelectedSpider) // 运行所选爬虫 + // authGroup.POST("/spiders-set-projects", routes.SetProjectsSelectedSpider) // 批量设置爬虫项目 + // } + // // 可配置爬虫 + // { + // authGroup.GET("/config_spiders/:id/config", routes.GetConfigSpiderConfig) // 获取可配置爬虫配置 + // authGroup.POST("/config_spiders/:id/config", routes.PostConfigSpiderConfig) // 更改可配置爬虫配置 + // authGroup.PUT("/config_spiders", routes.PutConfigSpider) // 添加可配置爬虫 + // authGroup.POST("/config_spiders/:id", routes.PostConfigSpider) // 修改可配置爬虫 + // authGroup.POST("/config_spiders/:id/upload", routes.UploadConfigSpider) // 上传可配置爬虫 + // authGroup.POST("/config_spiders/:id/spiderfile", routes.PostConfigSpiderSpiderfile) // 上传可配置爬虫 + // authGroup.GET("/config_spiders_templates", routes.GetConfigSpiderTemplateList) // 获取可配置爬虫模版列表 + // } + // // 任务 + // { + // authGroup.GET("/tasks", routes.GetTaskList) // 任务列表 + // authGroup.GET("/tasks/:id", routes.GetTask) // 任务详情 + // authGroup.PUT("/tasks", routes.PutTask) // 派发任务 + // authGroup.PUT("/tasks/batch", routes.PutBatchTasks) // 批量派发任务 + // authGroup.DELETE("/tasks/:id", routes.DeleteTask) // 删除任务 + // authGroup.DELETE("/tasks", routes.DeleteSelectedTask) // 删除多个任务 + // //authGroup.DELETE("/tasks_by_status", routes.DeleteTaskByStatus) // 删除指定状态的任务 + // authGroup.POST("/tasks/:id/cancel", routes.CancelTask) // 取消任务 + // authGroup.GET("/tasks/:id/log", routes.GetTaskLog) // 任务日志 + // authGroup.GET("/tasks/:id/error-log", routes.GetTaskErrorLog) // 任务错误日志 + // authGroup.GET("/tasks/:id/results", routes.GetTaskResults) // 任务结果 + // authGroup.GET("/tasks/:id/results/download", routes.DownloadTaskResultsCsv) // 下载任务结果 + // authGroup.POST("/tasks/:id/restart", routes.RestartTask) // 重新开始任务 + // authGroup.POST("/tasks-cancel", routes.CancelSelectedTask) // 批量取消任务 + // authGroup.POST("/tasks-restart", routes.RestartSelectedTask) // 批量重试任务 + // } + // // 系统任务/脚本 + // { + // authGroup.PUT("/system-tasks", routes.PutSystemTask) // 运行系统任务 + // authGroup.GET("/system-scripts", routes.GetSystemScripts) // 获取系统脚本列表 + // } + // // 定时任务 + // { + // authGroup.GET("/schedules", routes.GetScheduleList) // 定时任务列表 + // authGroup.GET("/schedules/:id", routes.GetSchedule) // 定时任务详情 + // authGroup.PUT("/schedules", routes.PutSchedule) // 创建定时任务 + // authGroup.PUT("/schedules/batch", routes.PutBatchSchedules) // 批量创建定时任务 + // authGroup.POST("/schedules/:id", routes.PostSchedule) // 修改定时任务 + // authGroup.DELETE("/schedules/:id", routes.DeleteSchedule) // 删除定时任务 + // authGroup.DELETE("/schedules", routes.DeleteBatchSchedules) // 批量删除定时任务 + // authGroup.POST("/schedules/:id/disable", routes.DisableSchedule) // 禁用定时任务 + // authGroup.POST("/schedules/:id/enable", routes.EnableSchedule) // 启用定时任务 + // authGroup.POST("/schedules-set-enabled", routes.SetEnabledSchedules) // 批量设置定时任务状态 + // } + // // 用户 + // { + // authGroup.GET("/users", routes.GetUserList) // 用户列表 + // authGroup.GET("/users/:id", routes.GetUser) // 用户详情 + // authGroup.POST("/users/:id", routes.PostUser) // 更改用户 + // authGroup.DELETE("/users/:id", routes.DeleteUser) // 删除用户 + // authGroup.PUT("/users-add", routes.PutUser) // 添加用户 + // authGroup.GET("/me", routes.GetMe) // 获取自己账户 + // authGroup.POST("/me", routes.PostMe) // 修改自己账户 + // authGroup.POST("/me/change-password", routes.PostMeChangePassword) // 修改自己密码 + // } + // // 系统 + // { + // authGroup.GET("/system/deps/:lang", routes.GetAllDepList) // 节点所有第三方依赖列表 + // authGroup.GET("/system/deps/:lang/:dep_name/json", routes.GetDepJson) // 节点第三方依赖JSON + // } + // // 全局变量 + // { + // authGroup.GET("/variables", routes.GetVariableList) // 列表 + // authGroup.PUT("/variable", routes.PutVariable) // 新增 + // authGroup.POST("/variable/:id", routes.PostVariable) // 修改 + // authGroup.DELETE("/variable/:id", routes.DeleteVariable) // 删除 + // } + // // 项目 + // { + // authGroup.GET("/projects", routes.GetProjectList) // 列表 + // authGroup.GET("/projects/tags", routes.GetProjectTags) // 项目标签 + // authGroup.PUT("/projects", routes.PutProject) // 修改 + // authGroup.POST("/projects/:id", routes.PostProject) // 新增 + // authGroup.DELETE("/projects/:id", routes.DeleteProject) // 删除 + // } + // // 操作 + // { + // //authGroup.GET("/actions", routes.GetActionList) // 操作列表 + // //authGroup.GET("/actions/:id", routes.GetAction) // 操作 + // authGroup.PUT("/actions", routes.PutAction) // 新增操作 + // //authGroup.POST("/actions/:id", routes.PostAction) // 修改操作 + // } + // // API Token + // { + // authGroup.GET("/tokens", routes.GetTokens) // 获取 Tokens + // authGroup.PUT("/tokens", routes.PutToken) // 添加 Token + // authGroup.DELETE("/tokens/:id", routes.DeleteToken) // 删除 Token + // } + // // 统计数据 + // authGroup.GET("/stats/home", routes.GetHomeStats) // 首页统计数据 + // // 文件 + // authGroup.GET("/file", routes.GetFile) // 获取文件 + // // Git + // authGroup.GET("/git/branches", routes.GetGitRemoteBranches) // 获取 Git 分支 + // authGroup.GET("/git/public-key", routes.GetGitSshPublicKey) // 获取 SSH 公钥 + // authGroup.GET("/git/commits", routes.GetGitCommits) // 获取 Git Commits + // authGroup.POST("/git/checkout", routes.PostGitCheckout) // 获取 Git Commits + // } + //} + + // 路由ping + //app.GET("/ping", routes.Ping) + + // 运行服务器 +} From cefe4c7343ddec91d5e539b663f0cde845535152 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Tue, 27 Apr 2021 11:37:18 +0800 Subject: [PATCH 09/19] updated description --- backend/cmd/handler.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/cmd/handler.go b/backend/cmd/handler.go index 747880a6..885d1281 100644 --- a/backend/cmd/handler.go +++ b/backend/cmd/handler.go @@ -11,8 +11,9 @@ func init() { var handlerCmd = &cobra.Command{ Use: "handler", - Short: "Start API server", - Long: `Start API server of Crawlab which serves data to frontend`, + Short: "Start task handler", + Long: `Start task handler service (worker) of Crawlab +which runs tasks assigned by master node`, Run: func(cmd *cobra.Command, args []string) { handler := apps.NewHandler() handler.Init() From 820334753a375f1be1b99927c0a944d76382cd04 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Tue, 27 Apr 2021 17:37:29 +0800 Subject: [PATCH 10/19] updated cli --- backend/apps/api.go | 34 +++++++++++++++------------------- backend/apps/base.go | 33 +++++++++++++++++++++++++++++---- backend/apps/handler.go | 7 ++++--- 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/backend/apps/api.go b/backend/apps/api.go index f9f7eacd..2cfd1cee 100644 --- a/backend/apps/api.go +++ b/backend/apps/api.go @@ -14,18 +14,16 @@ import ( "github.com/spf13/viper" "net" "net/http" - "os" - "os/signal" - "syscall" "time" ) type Api struct { BaseApp app *gin.Engine + srv *http.Server } -func (app *Api) Init() { +func (app *Api) init() { // initialize config _ = app.initModule("config", config.InitConfig) @@ -48,29 +46,27 @@ func (app *Api) Init() { _ = app.initModuleWithApp("routes", routes.InitRoutes) } -func (app *Api) Run() { +func (app *Api) run() { host := viper.GetString("server.host") port := viper.GetString("server.port") address := net.JoinHostPort(host, port) - srv := &http.Server{ + app.srv = &http.Server{ Handler: app.app, Addr: address, } - go func() { - if err := srv.ListenAndServe(); err != nil { - if err != http.ErrServerClosed { - log.Error("run server error:" + err.Error()) - } else { - log.Info("server graceful down") - } + if err := app.srv.ListenAndServe(); err != nil { + if err != http.ErrServerClosed { + log.Error("run server error:" + err.Error()) + } else { + log.Info("server graceful down") } - }() - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit - ctx2, cancel := context.WithTimeout(context.Background(), 20*time.Second) + } +} + +func (app *Api) stop() { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - if err := srv.Shutdown(ctx2); err != nil { + if err := app.srv.Shutdown(ctx); err != nil { log.Error("run server error:" + err.Error()) } } diff --git a/backend/apps/base.go b/backend/apps/base.go index b07ee94f..2c84fa13 100644 --- a/backend/apps/base.go +++ b/backend/apps/base.go @@ -4,24 +4,49 @@ import ( "fmt" "github.com/apex/log" "github.com/crawlab-team/go-trace" + "os" + "os/signal" + "syscall" ) type App interface { - Init() - Run() + init() + run() + stop() } type BaseApp struct { } -func (app *BaseApp) Init() { +func (app *BaseApp) init() { panic("implement me") } -func (app *BaseApp) Run() { +func (app *BaseApp) run() { panic("implement me") } +func (app *BaseApp) stop() { + panic("implement me") +} + +func (app *BaseApp) start() { + app.init() + go app.run() + app.waitForStop() + app.stop() +} + +func (app *BaseApp) Start() { + app.start() +} + +func (app *BaseApp) waitForStop() { + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit +} + func (app *BaseApp) initModule(name string, fn func() error) (err error) { if err := fn(); err != nil { log.Error(fmt.Sprintf("init %s error: %s", name, err.Error())) diff --git a/backend/apps/handler.go b/backend/apps/handler.go index dacb32c4..935143c6 100644 --- a/backend/apps/handler.go +++ b/backend/apps/handler.go @@ -1,6 +1,7 @@ package apps import ( + "github.com/apex/log" "github.com/crawlab-team/crawlab-core/services" ) @@ -8,12 +9,12 @@ type Handler struct { BaseApp } -func (app *Handler) Init() { +func (app *Handler) init() { _ = app.initModule("task-service", services.InitTaskService) } -func (app *Handler) Run() { - panic("implement me") +func (app *Handler) run() { + log.Info("handler has started") } func NewHandler() *Handler { From fd0f6fc37ab4a672c811ccd1ae6c8d490d0fbc41 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Thu, 29 Apr 2021 10:44:46 +0800 Subject: [PATCH 11/19] updated code structure --- backend/apps/api.go | 19 +++++++------ backend/apps/base.go | 57 +++------------------------------------ backend/apps/handler.go | 13 +++++---- backend/apps/master.go | 23 ++++++++++++++++ backend/apps/scheduler.go | 25 +++++++++++++++++ backend/apps/utils.go | 37 +++++++++++++++++++++++++ backend/apps/worker.go | 28 +++++++++++++++++++ backend/cmd/api.go | 10 +++---- backend/cmd/handler.go | 12 ++++----- backend/cmd/master.go | 22 +++++++++++++++ backend/cmd/worker.go | 23 ++++++++++++++++ backend/go.sum | 3 +++ 12 files changed, 192 insertions(+), 80 deletions(-) create mode 100644 backend/apps/master.go create mode 100644 backend/apps/scheduler.go create mode 100644 backend/apps/utils.go create mode 100644 backend/apps/worker.go create mode 100644 backend/cmd/master.go create mode 100644 backend/cmd/worker.go diff --git a/backend/apps/api.go b/backend/apps/api.go index 2cfd1cee..a650687f 100644 --- a/backend/apps/api.go +++ b/backend/apps/api.go @@ -18,26 +18,25 @@ import ( ) type Api struct { - BaseApp app *gin.Engine srv *http.Server } -func (app *Api) init() { +func (app *Api) Init() { // initialize config - _ = app.initModule("config", config.InitConfig) + _ = initModule("config", config.InitConfig) // initialize mongo - _ = app.initModule("mongo", mongo.InitMongo) + _ = initModule("mongo", mongo.InitMongo) // initialize redis - _ = app.initModule("redis", redis.InitRedis) + _ = initModule("redis", redis.InitRedis) // initialize model services - _ = app.initModule("mode-services", models.InitModelServices) + _ = initModule("mode-services", models.InitModelServices) // initialize controllers - _ = app.initModule("controllers", controllers.InitControllers) + _ = initModule("controllers", controllers.InitControllers) // initialize middlewares _ = app.initModuleWithApp("middlewares", middlewares.InitMiddlewares) @@ -46,7 +45,7 @@ func (app *Api) init() { _ = app.initModuleWithApp("routes", routes.InitRoutes) } -func (app *Api) run() { +func (app *Api) Run() { host := viper.GetString("server.host") port := viper.GetString("server.port") address := net.JoinHostPort(host, port) @@ -63,7 +62,7 @@ func (app *Api) run() { } } -func (app *Api) stop() { +func (app *Api) Stop() { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := app.srv.Shutdown(ctx); err != nil { @@ -72,7 +71,7 @@ func (app *Api) stop() { } func (app *Api) initModuleWithApp(name string, fn func(app *gin.Engine) error) (err error) { - return app.initModule(name, func() error { + return initModule(name, func() error { return fn(app.app) }) } diff --git a/backend/apps/base.go b/backend/apps/base.go index 2c84fa13..92770361 100644 --- a/backend/apps/base.go +++ b/backend/apps/base.go @@ -1,58 +1,7 @@ package apps -import ( - "fmt" - "github.com/apex/log" - "github.com/crawlab-team/go-trace" - "os" - "os/signal" - "syscall" -) - type App interface { - init() - run() - stop() -} - -type BaseApp struct { -} - -func (app *BaseApp) init() { - panic("implement me") -} - -func (app *BaseApp) run() { - panic("implement me") -} - -func (app *BaseApp) stop() { - panic("implement me") -} - -func (app *BaseApp) start() { - app.init() - go app.run() - app.waitForStop() - app.stop() -} - -func (app *BaseApp) Start() { - app.start() -} - -func (app *BaseApp) waitForStop() { - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit -} - -func (app *BaseApp) initModule(name string, fn func() error) (err error) { - if err := fn(); err != nil { - log.Error(fmt.Sprintf("init %s error: %s", name, err.Error())) - _ = trace.TraceError(err) - panic(err) - } - log.Info(fmt.Sprintf("initialized %s successfully", name)) - return nil + Init() + Run() + Stop() } diff --git a/backend/apps/handler.go b/backend/apps/handler.go index 935143c6..0701a105 100644 --- a/backend/apps/handler.go +++ b/backend/apps/handler.go @@ -2,21 +2,24 @@ package apps import ( "github.com/apex/log" - "github.com/crawlab-team/crawlab-core/services" + "github.com/crawlab-team/crawlab-core/grpc" ) type Handler struct { - BaseApp } -func (app *Handler) init() { - _ = app.initModule("task-service", services.InitTaskService) +func (app *Handler) Init() { + _ = initModule("grpc", grpc.InitGrpcServices) } -func (app *Handler) run() { +func (app *Handler) Run() { log.Info("handler has started") } +func (app *Handler) Stop() { + log.Info("handler has stopped") +} + func NewHandler() *Handler { return &Handler{} } diff --git a/backend/apps/master.go b/backend/apps/master.go new file mode 100644 index 00000000..bfbba2fa --- /dev/null +++ b/backend/apps/master.go @@ -0,0 +1,23 @@ +package apps + +type Master struct { + api *Api +} + +func (app *Master) Init() { + panic("implement me") +} + +func (app *Master) Run() { + panic("implement me") +} + +func (app *Master) Stop() { + panic("implement me") +} + +func NewMaster() *Master { + return &Master{ + api: NewApi(), + } +} diff --git a/backend/apps/scheduler.go b/backend/apps/scheduler.go new file mode 100644 index 00000000..56938767 --- /dev/null +++ b/backend/apps/scheduler.go @@ -0,0 +1,25 @@ +package apps + +import ( + "github.com/apex/log" + "github.com/crawlab-team/crawlab-core/grpc" +) + +type Scheduler struct { +} + +func (app *Scheduler) Init() { + _ = initModule("grpc", grpc.InitGrpcServices) +} + +func (app *Scheduler) Run() { + log.Info("scheduler has started") +} + +func (app *Scheduler) Stop() { + log.Info("scheduler has stopped") +} + +func NewScheduler() *Scheduler { + return &Scheduler{} +} diff --git a/backend/apps/utils.go b/backend/apps/utils.go new file mode 100644 index 00000000..17987882 --- /dev/null +++ b/backend/apps/utils.go @@ -0,0 +1,37 @@ +package apps + +import ( + "fmt" + "github.com/apex/log" + "github.com/crawlab-team/go-trace" + "os" + "os/signal" + "syscall" +) + +func Start(app App) { + start(app) +} + +func start(app App) { + app.Init() + go app.Run() + waitForStop() + app.Stop() +} + +func waitForStop() { + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit +} + +func initModule(name string, fn func() error) (err error) { + if err := fn(); err != nil { + log.Error(fmt.Sprintf("init %s error: %s", name, err.Error())) + _ = trace.TraceError(err) + panic(err) + } + log.Info(fmt.Sprintf("initialized %s successfully", name)) + return nil +} diff --git a/backend/apps/worker.go b/backend/apps/worker.go new file mode 100644 index 00000000..db1ccf09 --- /dev/null +++ b/backend/apps/worker.go @@ -0,0 +1,28 @@ +package apps + +import ( + "github.com/apex/log" + "github.com/crawlab-team/crawlab-core/grpc" +) + +type Worker struct { + handler *Handler +} + +func (app *Worker) Init() { + _ = initModule("grpc", grpc.InitGrpcServices) +} + +func (app *Worker) Run() { + log.Info("worker has started") +} + +func (app *Worker) Stop() { + log.Info("worker has stopped") +} + +func NewWorker() *Worker { + return &Worker{ + handler: NewHandler(), + } +} diff --git a/backend/cmd/api.go b/backend/cmd/api.go index fd265273..931bdbe9 100644 --- a/backend/cmd/api.go +++ b/backend/cmd/api.go @@ -10,12 +10,12 @@ func init() { } var apiCmd = &cobra.Command{ - Use: "api", - Short: "Start API server", - Long: `Start API server of Crawlab which serves data to frontend`, + Use: "api", + Aliases: []string{"A"}, + Short: "Start API server", + Long: `Start API server of Crawlab which serves data to frontend`, Run: func(cmd *cobra.Command, args []string) { api := apps.NewApi() - api.Init() - api.Run() + apps.Start(api) }, } diff --git a/backend/cmd/handler.go b/backend/cmd/handler.go index 885d1281..67abf39f 100644 --- a/backend/cmd/handler.go +++ b/backend/cmd/handler.go @@ -10,13 +10,13 @@ func init() { } var handlerCmd = &cobra.Command{ - Use: "handler", - Short: "Start task handler", - Long: `Start task handler service (worker) of Crawlab -which runs tasks assigned by master node`, + Use: "handler", + Aliases: []string{"H"}, + Short: "Start handler", + Long: `Start a handler instance of Crawlab +which runs tasks with given parameters`, Run: func(cmd *cobra.Command, args []string) { handler := apps.NewHandler() - handler.Init() - handler.Run() + apps.Start(handler) }, } diff --git a/backend/cmd/master.go b/backend/cmd/master.go new file mode 100644 index 00000000..91ba5584 --- /dev/null +++ b/backend/cmd/master.go @@ -0,0 +1,22 @@ +package cmd + +import ( + "crawlab/apps" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(masterCmd) +} + +var masterCmd = &cobra.Command{ + Use: "master", + Aliases: []string{"M"}, + Short: "Start master", + Long: `Start a master instance of Crawlab +which runs api and assign tasks to worker nodes`, + Run: func(cmd *cobra.Command, args []string) { + master := apps.NewMaster() + apps.Start(master) + }, +} diff --git a/backend/cmd/worker.go b/backend/cmd/worker.go new file mode 100644 index 00000000..30e85566 --- /dev/null +++ b/backend/cmd/worker.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "crawlab/apps" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(workerCmd) +} + +var workerCmd = &cobra.Command{ + Use: "worker", + Aliases: []string{"W"}, + Short: "Start worker", + Long: `Start a worker instance of Crawlab +serving in the worker node and executes tasks +assigned by the master node`, + Run: func(cmd *cobra.Command, args []string) { + worker := apps.NewWorker() + apps.Start(worker) + }, +} diff --git a/backend/go.sum b/backend/go.sum index 236692df..ba4f6b7f 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -208,6 +208,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR github.com/gorilla/websocket v1.0.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= @@ -654,6 +655,7 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d h1:HV9Z9qMhQEsdlvxNFELgQ11RkMzO3CMkjEySjCtuLes= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -661,6 +663,7 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 34e8beefdd8b7695472aed81c67ea5e4134498b5 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Thu, 29 Apr 2021 11:35:39 +0800 Subject: [PATCH 12/19] optimized code --- backend/apps/api.go | 9 +++++++-- backend/apps/base.go | 3 ++- backend/apps/handler.go | 12 ++++++++++-- backend/apps/master.go | 28 ++++++++++++++++++++++------ backend/apps/scheduler.go | 11 ++++++++++- backend/apps/utils.go | 13 ++++++++++--- backend/apps/worker.go | 21 ++++++++++++--------- backend/cmd/scheduler.go | 22 ++++++++++++++++++++++ 8 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 backend/cmd/scheduler.go diff --git a/backend/apps/api.go b/backend/apps/api.go index a650687f..58d271eb 100644 --- a/backend/apps/api.go +++ b/backend/apps/api.go @@ -33,7 +33,7 @@ func (app *Api) Init() { _ = initModule("redis", redis.InitRedis) // initialize model services - _ = initModule("mode-services", models.InitModelServices) + _ = initModule("model-services", models.InitModelServices) // initialize controllers _ = initModule("controllers", controllers.InitControllers) @@ -45,7 +45,7 @@ func (app *Api) Init() { _ = app.initModuleWithApp("routes", routes.InitRoutes) } -func (app *Api) Run() { +func (app *Api) Start() { host := viper.GetString("server.host") port := viper.GetString("server.port") address := net.JoinHostPort(host, port) @@ -62,9 +62,14 @@ func (app *Api) Run() { } } +func (app *Api) Wait() { + DefaultWait() +} + func (app *Api) Stop() { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() + if err := app.srv.Shutdown(ctx); err != nil { log.Error("run server error:" + err.Error()) } diff --git a/backend/apps/base.go b/backend/apps/base.go index 92770361..42fc1a99 100644 --- a/backend/apps/base.go +++ b/backend/apps/base.go @@ -2,6 +2,7 @@ package apps type App interface { Init() - Run() + Start() + Wait() Stop() } diff --git a/backend/apps/handler.go b/backend/apps/handler.go index 0701a105..80bdf033 100644 --- a/backend/apps/handler.go +++ b/backend/apps/handler.go @@ -2,6 +2,7 @@ package apps import ( "github.com/apex/log" + "github.com/crawlab-team/crawlab-core/config" "github.com/crawlab-team/crawlab-core/grpc" ) @@ -9,11 +10,18 @@ type Handler struct { } func (app *Handler) Init() { + // config + _ = initModule("config", config.InitConfig) + + // grpc _ = initModule("grpc", grpc.InitGrpcServices) } -func (app *Handler) Run() { - log.Info("handler has started") +func (app *Handler) Start() { +} + +func (app *Handler) Wait() { + DefaultWait() } func (app *Handler) Stop() { diff --git a/backend/apps/master.go b/backend/apps/master.go index bfbba2fa..c7257d92 100644 --- a/backend/apps/master.go +++ b/backend/apps/master.go @@ -1,23 +1,39 @@ package apps type Master struct { - api *Api + api *Api + scheduler *Scheduler + quit chan int } func (app *Master) Init() { - panic("implement me") + // api + initApp("api", app.api) + + // scheduler + initApp("scheduler", app.scheduler) } -func (app *Master) Run() { - panic("implement me") +func (app *Master) Start() { + go app.api.Start() + go app.scheduler.Start() +} + +func (app *Master) Wait() { + <-app.quit } func (app *Master) Stop() { - panic("implement me") + app.api.Stop() + app.scheduler.Stop() + + app.quit <- 1 } func NewMaster() *Master { return &Master{ - api: NewApi(), + api: NewApi(), + scheduler: NewScheduler(), + quit: make(chan int, 1), } } diff --git a/backend/apps/scheduler.go b/backend/apps/scheduler.go index 56938767..7d779fca 100644 --- a/backend/apps/scheduler.go +++ b/backend/apps/scheduler.go @@ -2,6 +2,7 @@ package apps import ( "github.com/apex/log" + "github.com/crawlab-team/crawlab-core/config" "github.com/crawlab-team/crawlab-core/grpc" ) @@ -9,13 +10,21 @@ type Scheduler struct { } func (app *Scheduler) Init() { + // config + _ = initModule("config", config.InitConfig) + + // grpc _ = initModule("grpc", grpc.InitGrpcServices) } -func (app *Scheduler) Run() { +func (app *Scheduler) Start() { log.Info("scheduler has started") } +func (app *Scheduler) Wait() { + DefaultWait() +} + func (app *Scheduler) Stop() { log.Info("scheduler has stopped") } diff --git a/backend/apps/utils.go b/backend/apps/utils.go index 17987882..20164f2c 100644 --- a/backend/apps/utils.go +++ b/backend/apps/utils.go @@ -15,12 +15,12 @@ func Start(app App) { func start(app App) { app.Init() - go app.Run() - waitForStop() + go app.Start() + app.Wait() app.Stop() } -func waitForStop() { +func DefaultWait() { quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit @@ -35,3 +35,10 @@ func initModule(name string, fn func() error) (err error) { log.Info(fmt.Sprintf("initialized %s successfully", name)) return nil } + +func initApp(name string, app App) { + _ = initModule(name, func() error { + app.Init() + return nil + }) +} diff --git a/backend/apps/worker.go b/backend/apps/worker.go index db1ccf09..add053e2 100644 --- a/backend/apps/worker.go +++ b/backend/apps/worker.go @@ -1,28 +1,31 @@ package apps -import ( - "github.com/apex/log" - "github.com/crawlab-team/crawlab-core/grpc" -) - type Worker struct { handler *Handler + quit chan int } func (app *Worker) Init() { - _ = initModule("grpc", grpc.InitGrpcServices) + initApp("handler", app.handler) } -func (app *Worker) Run() { - log.Info("worker has started") +func (app *Worker) Start() { + go app.handler.Start() +} + +func (app *Worker) Wait() { + <-app.quit } func (app *Worker) Stop() { - log.Info("worker has stopped") + app.handler.Stop() + + app.quit <- 1 } func NewWorker() *Worker { return &Worker{ handler: NewHandler(), + quit: make(chan int, 1), } } diff --git a/backend/cmd/scheduler.go b/backend/cmd/scheduler.go new file mode 100644 index 00000000..ae44a06a --- /dev/null +++ b/backend/cmd/scheduler.go @@ -0,0 +1,22 @@ +package cmd + +import ( + "crawlab/apps" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(schedulerCmd) +} + +var schedulerCmd = &cobra.Command{ + Use: "scheduler", + Aliases: []string{"S"}, + Short: "Start scheduler", + Long: `Start a scheduler instance of Crawlab +which assigns tasks to worker nodes to execute`, + Run: func(cmd *cobra.Command, args []string) { + scheduler := apps.NewScheduler() + apps.Start(scheduler) + }, +} From fb35493de9e90d6e6bf2b0b09d01d5a53a236d12 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Mon, 31 May 2021 16:26:17 +0800 Subject: [PATCH 13/19] updated apps --- backend/apps/api.go | 24 ++++++-------- backend/apps/base.go | 8 ----- backend/apps/handler.go | 7 ----- backend/apps/interfaces.go | 16 ++++++++++ backend/apps/master.go | 64 ++++++++++++++++++++++++++++---------- backend/apps/options.go | 15 +++++++++ backend/apps/scheduler.go | 7 ----- backend/apps/utils.go | 8 ++--- backend/apps/worker.go | 2 +- backend/cmd/master.go | 4 ++- backend/cmd/root.go | 11 +++---- backend/go.mod | 7 +++-- backend/go.sum | 35 +++++++++++++++++++++ 13 files changed, 137 insertions(+), 71 deletions(-) delete mode 100644 backend/apps/base.go create mode 100644 backend/apps/interfaces.go create mode 100644 backend/apps/options.go diff --git a/backend/apps/api.go b/backend/apps/api.go index 58d271eb..72497916 100644 --- a/backend/apps/api.go +++ b/backend/apps/api.go @@ -3,13 +3,11 @@ package apps import ( "context" "github.com/apex/log" - "github.com/crawlab-team/crawlab-core/config" "github.com/crawlab-team/crawlab-core/controllers" + "github.com/crawlab-team/crawlab-core/interfaces" "github.com/crawlab-team/crawlab-core/middlewares" - "github.com/crawlab-team/crawlab-core/models" "github.com/crawlab-team/crawlab-core/routes" "github.com/crawlab-team/crawlab-db/mongo" - "github.com/crawlab-team/crawlab-db/redis" "github.com/gin-gonic/gin" "github.com/spf13/viper" "net" @@ -18,23 +16,18 @@ import ( ) type Api struct { + // dependencies + interfaces.WithConfigPath + + // internals app *gin.Engine srv *http.Server } func (app *Api) Init() { - // initialize config - _ = initModule("config", config.InitConfig) - // initialize mongo _ = initModule("mongo", mongo.InitMongo) - // initialize redis - _ = initModule("redis", redis.InitRedis) - - // initialize model services - _ = initModule("model-services", models.InitModelServices) - // initialize controllers _ = initModule("controllers", controllers.InitControllers) @@ -82,8 +75,9 @@ func (app *Api) initModuleWithApp(name string, fn func(app *gin.Engine) error) ( } func NewApi() *Api { - app := gin.New() - return &Api{ - app: app, + api := &Api{ + app: gin.New(), } + api.Init() + return api } diff --git a/backend/apps/base.go b/backend/apps/base.go deleted file mode 100644 index 42fc1a99..00000000 --- a/backend/apps/base.go +++ /dev/null @@ -1,8 +0,0 @@ -package apps - -type App interface { - Init() - Start() - Wait() - Stop() -} diff --git a/backend/apps/handler.go b/backend/apps/handler.go index 80bdf033..9bf010bf 100644 --- a/backend/apps/handler.go +++ b/backend/apps/handler.go @@ -2,19 +2,12 @@ package apps import ( "github.com/apex/log" - "github.com/crawlab-team/crawlab-core/config" - "github.com/crawlab-team/crawlab-core/grpc" ) type Handler struct { } func (app *Handler) Init() { - // config - _ = initModule("config", config.InitConfig) - - // grpc - _ = initModule("grpc", grpc.InitGrpcServices) } func (app *Handler) Start() { diff --git a/backend/apps/interfaces.go b/backend/apps/interfaces.go new file mode 100644 index 00000000..8a96450e --- /dev/null +++ b/backend/apps/interfaces.go @@ -0,0 +1,16 @@ +package apps + +import "github.com/crawlab-team/crawlab-core/interfaces" + +type App interface { + Init() + Start() + Wait() + Stop() +} + +type MasterApp interface { + App + interfaces.WithConfigPath + SetRunOnMaster(ok bool) +} diff --git a/backend/apps/master.go b/backend/apps/master.go index c7257d92..8b222c6b 100644 --- a/backend/apps/master.go +++ b/backend/apps/master.go @@ -1,22 +1,37 @@ package apps +import ( + "github.com/crawlab-team/crawlab-core/config" + "github.com/crawlab-team/crawlab-core/interfaces" + "github.com/crawlab-team/crawlab-core/node/service" + "go.uber.org/dig" +) + type Master struct { - api *Api - scheduler *Scheduler - quit chan int + // settings + runOnMaster bool + + // dependencies + interfaces.WithConfigPath + masterSvc interfaces.NodeMasterService + + // modules + api *Api + + // internals + quit chan int +} + +func (app *Master) SetRunOnMaster(ok bool) { + app.runOnMaster = ok } func (app *Master) Init() { - // api - initApp("api", app.api) - - // scheduler - initApp("scheduler", app.scheduler) } func (app *Master) Start() { go app.api.Start() - go app.scheduler.Start() + go app.masterSvc.Start() } func (app *Master) Wait() { @@ -25,15 +40,32 @@ func (app *Master) Wait() { func (app *Master) Stop() { app.api.Stop() - app.scheduler.Stop() - app.quit <- 1 } -func NewMaster() *Master { - return &Master{ - api: NewApi(), - scheduler: NewScheduler(), - quit: make(chan int, 1), +func NewMaster(opts ...MasterOption) (app MasterApp) { + // master + m := &Master{ + WithConfigPath: config.NewConfigPathService(), + api: NewApi(), + quit: make(chan int, 1), } + + // apply options + for _, opt := range opts { + opt(m) + } + + // dependency injection + c := dig.New() + if err := c.Provide(service.ProvideMasterService(m.GetConfigPath())); err != nil { + panic(err) + } + if err := c.Invoke(func(masterSvc interfaces.NodeMasterService) { + m.masterSvc = masterSvc + }); err != nil { + panic(err) + } + + return m } diff --git a/backend/apps/options.go b/backend/apps/options.go new file mode 100644 index 00000000..80b5bdc1 --- /dev/null +++ b/backend/apps/options.go @@ -0,0 +1,15 @@ +package apps + +type MasterOption func(app MasterApp) + +func WithConfigPath(path string) MasterOption { + return func(app MasterApp) { + app.SetConfigPath(path) + } +} + +func WithRunOnMaster(ok bool) MasterOption { + return func(app MasterApp) { + app.SetRunOnMaster(ok) + } +} diff --git a/backend/apps/scheduler.go b/backend/apps/scheduler.go index 7d779fca..8bb8662a 100644 --- a/backend/apps/scheduler.go +++ b/backend/apps/scheduler.go @@ -2,19 +2,12 @@ package apps import ( "github.com/apex/log" - "github.com/crawlab-team/crawlab-core/config" - "github.com/crawlab-team/crawlab-core/grpc" ) type Scheduler struct { } func (app *Scheduler) Init() { - // config - _ = initModule("config", config.InitConfig) - - // grpc - _ = initModule("grpc", grpc.InitGrpcServices) } func (app *Scheduler) Start() { diff --git a/backend/apps/utils.go b/backend/apps/utils.go index 20164f2c..c223f8c5 100644 --- a/backend/apps/utils.go +++ b/backend/apps/utils.go @@ -3,10 +3,8 @@ package apps import ( "fmt" "github.com/apex/log" + "github.com/crawlab-team/crawlab-core/utils" "github.com/crawlab-team/go-trace" - "os" - "os/signal" - "syscall" ) func Start(app App) { @@ -21,9 +19,7 @@ func start(app App) { } func DefaultWait() { - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit + utils.DefaultWait() } func initModule(name string, fn func() error) (err error) { diff --git a/backend/apps/worker.go b/backend/apps/worker.go index add053e2..a3fe5d83 100644 --- a/backend/apps/worker.go +++ b/backend/apps/worker.go @@ -6,7 +6,7 @@ type Worker struct { } func (app *Worker) Init() { - initApp("handler", app.handler) + initApp("handler", app.handler) // handler } func (app *Worker) Start() { diff --git a/backend/cmd/master.go b/backend/cmd/master.go index 91ba5584..065d37b8 100644 --- a/backend/cmd/master.go +++ b/backend/cmd/master.go @@ -16,7 +16,9 @@ var masterCmd = &cobra.Command{ Long: `Start a master instance of Crawlab which runs api and assign tasks to worker nodes`, Run: func(cmd *cobra.Command, args []string) { - master := apps.NewMaster() + master := apps.NewMaster( + apps.WithRunOnMaster(runOnMaster), + ) apps.Start(master) }, } diff --git a/backend/cmd/root.go b/backend/cmd/root.go index 6b2eb743..aa53dc1b 100644 --- a/backend/cmd/root.go +++ b/backend/cmd/root.go @@ -10,7 +10,8 @@ import ( var ( // Used for flags. - cfgFile string + cfgFile string + runOnMaster bool rootCmd = &cobra.Command{ Use: "crawlab", @@ -30,12 +31,8 @@ func Execute() error { func init() { cobra.OnInitialize(initConfig) - //rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") - //rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") - //rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") - //rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") - //viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) - //viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) + rootCmd.PersistentFlags().BoolVar(&runOnMaster, "runOnMaster", false, "Whether to run tasks on master node (default: false)") + _ = viper.BindPFlag("runOnMaster", rootCmd.PersistentFlags().Lookup("runOnMaster")) } func initConfig() { diff --git a/backend/go.mod b/backend/go.mod index 64e7f858..c55f2170 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -9,17 +9,18 @@ replace ( github.com/crawlab-team/crawlab-grpc => /Users/marvzhang/projects/crawlab-team/crawlab-grpc/dist/go github.com/crawlab-team/crawlab-log => /Users/marvzhang/projects/crawlab-team/crawlab-log github.com/crawlab-team/crawlab-vcs => /Users/marvzhang/projects/crawlab-team/crawlab-vcs + github.com/crawlab-team/goseaweedfs => /Users/marvzhang/projects/crawlab-team/goseaweedfs github.com/crawlab-team/go-trace => /Users/marvzhang/projects/crawlab-team/go-trace - github.com/linxGnu/goseaweedfs => /Users/marvzhang/projects/tikazyq/goseaweedfs ) require ( github.com/apex/log v1.9.0 - github.com/crawlab-team/crawlab-core v0.0.1 + github.com/crawlab-team/crawlab-core v0.0.0 github.com/crawlab-team/crawlab-db v0.0.2 - github.com/crawlab-team/go-trace v0.0.0 + github.com/crawlab-team/go-trace v0.1.0 github.com/gin-gonic/gin v1.6.3 github.com/mitchellh/go-homedir v1.1.0 github.com/spf13/cobra v1.1.3 github.com/spf13/viper v1.7.1 + go.uber.org/dig v1.10.0 ) diff --git a/backend/go.sum b/backend/go.sum index ba4f6b7f..91824f71 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -27,6 +27,7 @@ github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBb github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= @@ -64,6 +65,8 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/crawlab-team/goseaweedfs v0.1.6 h1:4Qmz75e65h4gbj0/sTM7pPVFwVJl8MihXf28igy2cFc= +github.com/crawlab-team/goseaweedfs v0.1.6/go.mod h1:u+rwfqb0rnYllTLjCctE/z1Yp+TC8L+CbbWH8E2NstA= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -197,6 +200,7 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= @@ -210,6 +214,8 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -259,6 +265,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= @@ -380,6 +388,7 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -410,6 +419,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= @@ -491,6 +501,7 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3Ifn github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -503,6 +514,8 @@ go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY= +go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -515,8 +528,11 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -536,6 +552,8 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -555,7 +573,9 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -569,6 +589,8 @@ golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -593,16 +615,22 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg= golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -630,11 +658,16 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -654,6 +687,7 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d h1:HV9Z9qMhQEsdlvxNFELgQ11RkMzO3CMkjEySjCtuLes= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -676,6 +710,7 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= From f44a29cff13f41b8acdf6e55ddc506f83ffcea5e Mon Sep 17 00:00:00 2001 From: marvzhang Date: Wed, 30 Jun 2021 10:29:26 +0800 Subject: [PATCH 14/19] updated go.sum --- backend/go.sum | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/go.sum b/backend/go.sum index 91824f71..22800059 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -393,6 +393,10 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= +github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E= +github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= From 5b2aff713ea08a0e74a54a9d35695f7e88c91d6d Mon Sep 17 00:00:00 2001 From: marvzhang Date: Sat, 10 Jul 2021 21:47:30 +0800 Subject: [PATCH 15/19] added params to cmd --- backend/apps/interfaces.go | 11 +++- backend/apps/master.go | 13 +++- backend/apps/options.go | 24 +++++++- backend/apps/worker.go | 60 +++++++++++++++---- backend/cmd/master.go | 38 +++++++++++- backend/cmd/root.go | 6 +- backend/cmd/worker.go | 37 +++++++++++- backend/conf/config.yml | 8 ++- backend/test/config-master.json | 10 ++++ .../test/config-worker-invalid-auth-key.json | 10 ++++ backend/test/config-worker.json | 10 ++++ 11 files changed, 203 insertions(+), 24 deletions(-) create mode 100644 backend/test/config-master.json create mode 100644 backend/test/config-worker-invalid-auth-key.json create mode 100644 backend/test/config-worker.json diff --git a/backend/apps/interfaces.go b/backend/apps/interfaces.go index 8a96450e..dbdd24fd 100644 --- a/backend/apps/interfaces.go +++ b/backend/apps/interfaces.go @@ -9,8 +9,17 @@ type App interface { Stop() } -type MasterApp interface { +type NodeApp interface { App interfaces.WithConfigPath + SetGrpcAddress(address interfaces.Address) +} + +type MasterApp interface { + NodeApp SetRunOnMaster(ok bool) } + +type WorkerApp interface { + NodeApp +} diff --git a/backend/apps/master.go b/backend/apps/master.go index 8b222c6b..1fc86345 100644 --- a/backend/apps/master.go +++ b/backend/apps/master.go @@ -10,6 +10,7 @@ import ( type Master struct { // settings runOnMaster bool + grpcAddress interfaces.Address // dependencies interfaces.WithConfigPath @@ -22,6 +23,10 @@ type Master struct { quit chan int } +func (app *Master) SetGrpcAddress(address interfaces.Address) { + app.grpcAddress = address +} + func (app *Master) SetRunOnMaster(ok bool) { app.runOnMaster = ok } @@ -56,9 +61,15 @@ func NewMaster(opts ...MasterOption) (app MasterApp) { opt(m) } + // service options + var svcOpts []service.Option + if m.grpcAddress != nil { + svcOpts = append(svcOpts, service.WithAddress(m.grpcAddress)) + } + // dependency injection c := dig.New() - if err := c.Provide(service.ProvideMasterService(m.GetConfigPath())); err != nil { + if err := c.Provide(service.ProvideMasterService(m.GetConfigPath(), svcOpts...)); err != nil { panic(err) } if err := c.Invoke(func(masterSvc interfaces.NodeMasterService) { diff --git a/backend/apps/options.go b/backend/apps/options.go index 80b5bdc1..70280058 100644 --- a/backend/apps/options.go +++ b/backend/apps/options.go @@ -1,15 +1,37 @@ package apps +import "github.com/crawlab-team/crawlab-core/interfaces" + type MasterOption func(app MasterApp) -func WithConfigPath(path string) MasterOption { +func WithMasterConfigPath(path string) MasterOption { return func(app MasterApp) { app.SetConfigPath(path) } } +func WithMasterGrpcAddress(address interfaces.Address) MasterOption { + return func(app MasterApp) { + app.SetGrpcAddress(address) + } +} + func WithRunOnMaster(ok bool) MasterOption { return func(app MasterApp) { app.SetRunOnMaster(ok) } } + +type WorkerOption func(app WorkerApp) + +func WithWorkerConfigPath(path string) WorkerOption { + return func(app WorkerApp) { + app.SetConfigPath(path) + } +} + +func WithWorkerGrpcAddress(address interfaces.Address) WorkerOption { + return func(app WorkerApp) { + app.SetGrpcAddress(address) + } +} diff --git a/backend/apps/worker.go b/backend/apps/worker.go index a3fe5d83..7d1200d7 100644 --- a/backend/apps/worker.go +++ b/backend/apps/worker.go @@ -1,16 +1,33 @@ package apps +import ( + "github.com/crawlab-team/crawlab-core/config" + "github.com/crawlab-team/crawlab-core/interfaces" + "github.com/crawlab-team/crawlab-core/node/service" + "go.uber.org/dig" +) + type Worker struct { - handler *Handler - quit chan int + // settings + grpcAddress interfaces.Address + + // dependencies + interfaces.WithConfigPath + workerSvc interfaces.NodeWorkerService + + // internals + quit chan int +} + +func (app *Worker) SetGrpcAddress(address interfaces.Address) { + app.grpcAddress = address } func (app *Worker) Init() { - initApp("handler", app.handler) // handler } func (app *Worker) Start() { - go app.handler.Start() + go app.workerSvc.Start() } func (app *Worker) Wait() { @@ -18,14 +35,37 @@ func (app *Worker) Wait() { } func (app *Worker) Stop() { - app.handler.Stop() - app.quit <- 1 } -func NewWorker() *Worker { - return &Worker{ - handler: NewHandler(), - quit: make(chan int, 1), +func NewWorker(opts ...WorkerOption) (app *Worker) { + // worker + w := &Worker{ + WithConfigPath: config.NewConfigPathService(), + quit: make(chan int, 1), } + + // apply options + for _, opt := range opts { + opt(w) + } + + // service options + var svcOpts []service.Option + if w.grpcAddress != nil { + svcOpts = append(svcOpts, service.WithAddress(w.grpcAddress)) + } + + // dependency injection + c := dig.New() + if err := c.Provide(service.ProvideWorkerService(w.GetConfigPath(), svcOpts...)); err != nil { + panic(err) + } + if err := c.Invoke(func(workerSvc interfaces.NodeWorkerService) { + w.workerSvc = workerSvc + }); err != nil { + panic(err) + } + + return w } diff --git a/backend/cmd/master.go b/backend/cmd/master.go index 065d37b8..2e739d29 100644 --- a/backend/cmd/master.go +++ b/backend/cmd/master.go @@ -2,11 +2,26 @@ package cmd import ( "crawlab/apps" + "fmt" + "github.com/crawlab-team/crawlab-core/entity" "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + runOnMaster bool + masterConfigPath string + masterGrpcAddress string ) func init() { rootCmd.AddCommand(masterCmd) + + masterCmd.PersistentFlags().StringVarP(&masterConfigPath, "config-path", "c", "", "Config path of master node") + _ = viper.BindPFlag("configPath", masterCmd.PersistentFlags().Lookup("configPath")) + + masterCmd.PersistentFlags().StringVarP(&masterGrpcAddress, "grpc-address", "g", "", "gRPC address of master node") + _ = viper.BindPFlag("grpcAddress", masterCmd.PersistentFlags().Lookup("grpcAddress")) } var masterCmd = &cobra.Command{ @@ -16,9 +31,26 @@ var masterCmd = &cobra.Command{ Long: `Start a master instance of Crawlab which runs api and assign tasks to worker nodes`, Run: func(cmd *cobra.Command, args []string) { - master := apps.NewMaster( - apps.WithRunOnMaster(runOnMaster), - ) + // options + var opts []apps.MasterOption + if masterConfigPath != "" { + opts = append(opts, apps.WithMasterConfigPath(masterConfigPath)) + viper.Set("config.path", masterConfigPath) + } + opts = append(opts, apps.WithRunOnMaster(runOnMaster)) + if masterGrpcAddress != "" { + address, err := entity.NewAddressFromString(masterGrpcAddress) + if err != nil { + fmt.Println(fmt.Sprintf("invalid grpc-address: %s", masterGrpcAddress)) + } + opts = append(opts, apps.WithMasterGrpcAddress(address)) + viper.Set("grpc.client.address", masterGrpcAddress) + } + + // app + master := apps.NewMaster(opts...) + + // start apps.Start(master) }, } diff --git a/backend/cmd/root.go b/backend/cmd/root.go index aa53dc1b..067d4d74 100644 --- a/backend/cmd/root.go +++ b/backend/cmd/root.go @@ -10,8 +10,7 @@ import ( var ( // Used for flags. - cfgFile string - runOnMaster bool + cfgFile string rootCmd = &cobra.Command{ Use: "crawlab", @@ -30,9 +29,6 @@ func Execute() error { func init() { cobra.OnInitialize(initConfig) - - rootCmd.PersistentFlags().BoolVar(&runOnMaster, "runOnMaster", false, "Whether to run tasks on master node (default: false)") - _ = viper.BindPFlag("runOnMaster", rootCmd.PersistentFlags().Lookup("runOnMaster")) } func initConfig() { diff --git a/backend/cmd/worker.go b/backend/cmd/worker.go index 30e85566..93a6ca1d 100644 --- a/backend/cmd/worker.go +++ b/backend/cmd/worker.go @@ -2,11 +2,25 @@ package cmd import ( "crawlab/apps" + "fmt" + "github.com/crawlab-team/crawlab-core/entity" "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + workerConfigPath string + workerGrpcAddress string ) func init() { rootCmd.AddCommand(workerCmd) + + workerCmd.PersistentFlags().StringVarP(&workerConfigPath, "config-path", "c", "", "Config path of worker node") + _ = viper.BindPFlag("configPath", workerCmd.PersistentFlags().Lookup("configPath")) + + workerCmd.PersistentFlags().StringVarP(&workerGrpcAddress, "grpc-address", "g", "", "gRPC address of worker node") + _ = viper.BindPFlag("grpcAddress", workerCmd.PersistentFlags().Lookup("grpcAddress")) } var workerCmd = &cobra.Command{ @@ -17,7 +31,26 @@ var workerCmd = &cobra.Command{ serving in the worker node and executes tasks assigned by the master node`, Run: func(cmd *cobra.Command, args []string) { - worker := apps.NewWorker() - apps.Start(worker) + // options + var opts []apps.WorkerOption + if workerConfigPath != "" { + opts = append(opts, apps.WithWorkerConfigPath(workerConfigPath)) + viper.Set("config.path", workerConfigPath) + } + if workerGrpcAddress != "" { + address, err := entity.NewAddressFromString(workerGrpcAddress) + if err != nil { + fmt.Println(fmt.Sprintf("invalid grpc-address: %s", workerGrpcAddress)) + return + } + opts = append(opts, apps.WithWorkerGrpcAddress(address)) + viper.Set("grpc.client.address", workerGrpcAddress) + } + + // app + master := apps.NewWorker(opts...) + + // start + apps.Start(master) }, } diff --git a/backend/conf/config.yml b/backend/conf/config.yml index 8f69d28f..302fe70f 100644 --- a/backend/conf/config.yml +++ b/backend/conf/config.yml @@ -61,4 +61,10 @@ notification: senderIdentity: '' smtp: user: '' - password: '' \ No newline at end of file + password: '' +config: + path: '' +grpc: + client: + address: localhost:9666 + authKey: Crawlab2021! \ No newline at end of file diff --git a/backend/test/config-master.json b/backend/test/config-master.json new file mode 100644 index 00000000..98ead88c --- /dev/null +++ b/backend/test/config-master.json @@ -0,0 +1,10 @@ +{ + "key": "master", + "is_master": true, + "name": "master", + "ip": "", + "mac": "", + "hostname": "", + "description": "", + "auth_key": "Crawlab2021!" +} \ No newline at end of file diff --git a/backend/test/config-worker-invalid-auth-key.json b/backend/test/config-worker-invalid-auth-key.json new file mode 100644 index 00000000..5c724985 --- /dev/null +++ b/backend/test/config-worker-invalid-auth-key.json @@ -0,0 +1,10 @@ +{ + "key": "worker-invalid-auth-key", + "is_master": false, + "name": "worker", + "ip": "", + "mac": "", + "hostname": "", + "description": "", + "auth_key": "invalid-auth-key" +} \ No newline at end of file diff --git a/backend/test/config-worker.json b/backend/test/config-worker.json new file mode 100644 index 00000000..f88c1630 --- /dev/null +++ b/backend/test/config-worker.json @@ -0,0 +1,10 @@ +{ + "key": "worker", + "is_master": false, + "name": "worker", + "ip": "", + "mac": "", + "hostname": "", + "description": "", + "auth_key": "Crawlab2021!" +} \ No newline at end of file From 553fbbc1f8fceae4c9dfd2043cbb02f18b6fc694 Mon Sep 17 00:00:00 2001 From: marvzhang Date: Sat, 10 Jul 2021 22:22:02 +0800 Subject: [PATCH 16/19] updated cmd --- backend/cmd/master.go | 3 ++- backend/cmd/worker.go | 2 +- backend/conf/config.yml | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/cmd/master.go b/backend/cmd/master.go index 2e739d29..bd9974aa 100644 --- a/backend/cmd/master.go +++ b/backend/cmd/master.go @@ -44,7 +44,8 @@ which runs api and assign tasks to worker nodes`, fmt.Println(fmt.Sprintf("invalid grpc-address: %s", masterGrpcAddress)) } opts = append(opts, apps.WithMasterGrpcAddress(address)) - viper.Set("grpc.client.address", masterGrpcAddress) + viper.Set("grpc.address", masterGrpcAddress) + viper.Set("grpc.server.address", masterGrpcAddress) } // app diff --git a/backend/cmd/worker.go b/backend/cmd/worker.go index 93a6ca1d..8930f478 100644 --- a/backend/cmd/worker.go +++ b/backend/cmd/worker.go @@ -44,7 +44,7 @@ assigned by the master node`, return } opts = append(opts, apps.WithWorkerGrpcAddress(address)) - viper.Set("grpc.client.address", workerGrpcAddress) + viper.Set("grpc.address", workerGrpcAddress) } // app diff --git a/backend/conf/config.yml b/backend/conf/config.yml index 302fe70f..d4c59e32 100644 --- a/backend/conf/config.yml +++ b/backend/conf/config.yml @@ -65,6 +65,7 @@ notification: config: path: '' grpc: - client: - address: localhost:9666 + address: localhost:9666 + server: + address: 0.0.0.0:9666 authKey: Crawlab2021! \ No newline at end of file From db6414aa5bc9d860a6aca75c629e094aa11490ff Mon Sep 17 00:00:00 2001 From: marvzhang Date: Thu, 15 Jul 2021 21:29:15 +0800 Subject: [PATCH 17/19] updated dependencies --- backend/cmd/master.go | 7 ++ backend/cmd/worker.go | 7 ++ backend/conf/config.yml | 92 ++++++++++++-------------- backend/go.mod | 15 +---- backend/go.sum | 143 ++++++++++++++++++++++++++++++---------- 5 files changed, 168 insertions(+), 96 deletions(-) diff --git a/backend/cmd/master.go b/backend/cmd/master.go index bd9974aa..d85e3e51 100644 --- a/backend/cmd/master.go +++ b/backend/cmd/master.go @@ -12,6 +12,7 @@ var ( runOnMaster bool masterConfigPath string masterGrpcAddress string + masterGrpcAuthKey string ) func init() { @@ -22,6 +23,9 @@ func init() { masterCmd.PersistentFlags().StringVarP(&masterGrpcAddress, "grpc-address", "g", "", "gRPC address of master node") _ = viper.BindPFlag("grpcAddress", masterCmd.PersistentFlags().Lookup("grpcAddress")) + + masterCmd.PersistentFlags().StringVarP(&masterGrpcAuthKey, "grpc-auth-key", "a", "", "gRPC auth key of master node") + _ = viper.BindPFlag("grpcAuthKey", masterCmd.PersistentFlags().Lookup("grpcAuthKey")) } var masterCmd = &cobra.Command{ @@ -47,6 +51,9 @@ which runs api and assign tasks to worker nodes`, viper.Set("grpc.address", masterGrpcAddress) viper.Set("grpc.server.address", masterGrpcAddress) } + if masterGrpcAuthKey != "" { + viper.Set("grpc.authKey", masterGrpcAuthKey) + } // app master := apps.NewMaster(opts...) diff --git a/backend/cmd/worker.go b/backend/cmd/worker.go index 8930f478..490cdd47 100644 --- a/backend/cmd/worker.go +++ b/backend/cmd/worker.go @@ -11,6 +11,7 @@ import ( var ( workerConfigPath string workerGrpcAddress string + workerGrpcAuthKey string ) func init() { @@ -21,6 +22,9 @@ func init() { workerCmd.PersistentFlags().StringVarP(&workerGrpcAddress, "grpc-address", "g", "", "gRPC address of worker node") _ = viper.BindPFlag("grpcAddress", workerCmd.PersistentFlags().Lookup("grpcAddress")) + + workerCmd.PersistentFlags().StringVarP(&workerGrpcAuthKey, "grpc-auth-key", "a", "", "gRPC auth key of worker node") + _ = viper.BindPFlag("grpcAuthKey", workerCmd.PersistentFlags().Lookup("grpcAuthKey")) } var workerCmd = &cobra.Command{ @@ -46,6 +50,9 @@ assigned by the master node`, opts = append(opts, apps.WithWorkerGrpcAddress(address)) viper.Set("grpc.address", workerGrpcAddress) } + if workerGrpcAuthKey != "" { + viper.Set("grpc.authKey", workerGrpcAuthKey) + } // app master := apps.NewWorker(opts...) diff --git a/backend/conf/config.yml b/backend/conf/config.yml index d4c59e32..b4e90764 100644 --- a/backend/conf/config.yml +++ b/backend/conf/config.yml @@ -1,5 +1,3 @@ -api: - address: "localhost:8000" mongo: host: localhost port: 27017 @@ -7,31 +5,23 @@ mongo: username: "" password: "" authSource: "admin" -redis: - address: localhost - password: "" - database: 1 - port: 6379 -log: - level: info - path: "/logs" server: host: 0.0.0.0 port: 8000 - master: true - secret: "crawlab" - register: - # type 填 mac/ip/customName, 如果是ip,则需要手动指定IP, 如果是 customName, 需填写你的 customNodeName - type: "mac" - customNodeName: "" # 自定义节点名称, default node1,只有在type = customName 时生效 - ip: "" - lang: # 安装语言环境, Y 为安装,N 为不安装 - python: "Y" - node: "N" - java: "N" - dotnet: "N" - php: "N" - scripts: "/app/backend/scripts" +# master: true +# secret: "crawlab" +# register: +# # type 填 mac/ip/customName, 如果是ip,则需要手动指定IP, 如果是 customName, 需填写你的 customNodeName +# type: "mac" +# customNodeName: "" # 自定义节点名称, default node1,只有在type = customName 时生效 +# ip: "" +# lang: # 安装语言环境, Y 为安装,N 为不安装 +# python: "Y" +# node: "N" +# java: "N" +# dotnet: "N" +# php: "N" +# scripts: "/app/backend/scripts" spider: fs: "/spiders" workspace: "/workspace" @@ -39,33 +29,35 @@ spider: task: workers: 16 cancelWaitSeconds: 30 -other: - tmppath: "/tmp" -version: 0.5.1 -setting: - crawlabLogToES: "N" # Send crawlab runtime log to ES, open this option "Y", remember to set esClient - crawlabLogIndex: "crawlab-log" - allowRegister: "N" - enableTutorial: "N" - runOnMaster: "Y" - demoSpiders: "N" - checkScrapy: "Y" - autoInstall: "Y" - esClient: "" # Your ES client, for example, http://192.168.1.1:9200 or http://your-domain.com, if not use es, set empty - spiderLogIndex: "spider-log" # Index pattern for kibana, need to config on kibana -notification: - mail: - server: '' - port: '' - senderEmail: '' - senderIdentity: '' - smtp: - user: '' - password: '' -config: - path: '' +# TODO: implement +#setting: +# crawlabLogToES: "N" # Send crawlab runtime log to ES, open this option "Y", remember to set esClient +# crawlabLogIndex: "crawlab-log" +# allowRegister: "N" +# enableTutorial: "N" +# runOnMaster: "Y" +# demoSpiders: "N" +# checkScrapy: "Y" +# autoInstall: "Y" +# esClient: "" # Your ES client, for example, http://192.168.1.1:9200 or http://your-domain.com, if not use es, set empty +# spiderLogIndex: "spider-log" # Index pattern for kibana, need to config on kibana +# TODO: implement +#notification: +# mail: +# server: '' +# port: '' +# senderEmail: '' +# senderIdentity: '' +# smtp: +# user: '' +# password: '' grpc: address: localhost:9666 server: address: 0.0.0.0:9666 - authKey: Crawlab2021! \ No newline at end of file + authKey: Crawlab2021! +fs: + filer: + proxy: http://localhost:8888 + url: http://localhost:8000/filer + authKey: Crawlab2021! diff --git a/backend/go.mod b/backend/go.mod index c55f2170..a47579d1 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -2,21 +2,10 @@ module crawlab go 1.15 -replace ( - github.com/crawlab-team/crawlab-core => /Users/marvzhang/projects/crawlab-team/crawlab-core - github.com/crawlab-team/crawlab-db => /Users/marvzhang/projects/crawlab-team/crawlab-db - github.com/crawlab-team/crawlab-fs => /Users/marvzhang/projects/crawlab-team/crawlab-fs - github.com/crawlab-team/crawlab-grpc => /Users/marvzhang/projects/crawlab-team/crawlab-grpc/dist/go - github.com/crawlab-team/crawlab-log => /Users/marvzhang/projects/crawlab-team/crawlab-log - github.com/crawlab-team/crawlab-vcs => /Users/marvzhang/projects/crawlab-team/crawlab-vcs - github.com/crawlab-team/goseaweedfs => /Users/marvzhang/projects/crawlab-team/goseaweedfs - github.com/crawlab-team/go-trace => /Users/marvzhang/projects/crawlab-team/go-trace -) - require ( github.com/apex/log v1.9.0 - github.com/crawlab-team/crawlab-core v0.0.0 - github.com/crawlab-team/crawlab-db v0.0.2 + github.com/crawlab-team/crawlab-core v0.6.0-beta.20210715 + github.com/crawlab-team/crawlab-db v0.1.0 github.com/crawlab-team/go-trace v0.1.0 github.com/gin-gonic/gin v1.6.3 github.com/mitchellh/go-homedir v1.1.0 diff --git a/backend/go.sum b/backend/go.sum index 22800059..9edcbf02 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -4,6 +4,7 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3 h1:AVXDdKsrtX33oR9fbCMu/+c1o8Ofjq6Ku/MInaLVg5Y= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -14,19 +15,27 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/sprig v2.16.0+incompatible h1:QZbMUPxRQ50EKAq3LFMnxddMu88/EUUG3qmxwtDmPsY= github.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= -github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/StackExchange/wmi v1.2.0 h1:noJEYkMQVlFCEAc+2ma5YyRhlfjcWfZqk5sBRYozdyM= +github.com/StackExchange/wmi v1.2.0/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/Unknwon/goconfig v0.0.0-20191126170842-860a72fb44fd/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw= +github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= @@ -64,9 +73,30 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/crawlab-team/crawlab-core v0.0.1/go.mod h1:6dJHMvrmIJbfYHhYNeGZkGOLEBvur+yGiFzLCRXx92k= +github.com/crawlab-team/crawlab-core v0.6.0-beta.20210715 h1:2ryY/+sdRR71Cd0dN7NvR6S9toVlm0LloaJC82NnZcg= +github.com/crawlab-team/crawlab-core v0.6.0-beta.20210715/go.mod h1:OXO0hN3YwKN0hnJoa6bJ/DGWZjE4XzVAv+pfmCzOmds= +github.com/crawlab-team/crawlab-db v0.0.2/go.mod h1:o7o4rbcyAWlFGHg9VS7V7tM/GqRq+N2mnAXO71cZA78= +github.com/crawlab-team/crawlab-db v0.1.0 h1:6dTVNb5+7cDkH8fkKOkFALk8laWNOuorYm3ZEKsvFLI= +github.com/crawlab-team/crawlab-db v0.1.0/go.mod h1:t0VidSjXKzQgACqNSQV5wusXncFtL6lGEiQTbLfNR04= +github.com/crawlab-team/crawlab-fs v0.0.0/go.mod h1:k2VXprQspLAmbgO5sSpqMjg/xP4iKDkW4RyTWY8eTZM= +github.com/crawlab-team/crawlab-fs v0.1.0 h1:iKSJJY4Wvea8Qss+zC/tLiZ371VeV75Z3cuqlsxydzY= +github.com/crawlab-team/crawlab-fs v0.1.0/go.mod h1:dOE0TeWPDz9krwzt1H72rjj0Fn/aHe53yn7GoOZHD0s= +github.com/crawlab-team/crawlab-grpc v0.1.0 h1:cCAvQMyXCuUumek2EmYBFRU4UwnC84454vwc+vg4PeE= +github.com/crawlab-team/crawlab-grpc v0.1.0/go.mod h1:W9Yee6xfesxoaqS5K1sF1I1zlH+i6xqwy4lyoBTOdkc= +github.com/crawlab-team/crawlab-log v0.1.0 h1:0t+lZEojs3Vqb/bMkk2qs3I+1+XdwKG3pMTfeK5PZWM= +github.com/crawlab-team/crawlab-log v0.1.0/go.mod h1:N8nTTKEbr9ZQSlmw0+HNB4ZAMQF4yVMaJLx8YhXvhNo= +github.com/crawlab-team/crawlab-vcs v0.1.0 h1:LjtKOOFzx1o7vvgGppC7jt/8lznyvFwwXBYggbSW9+4= +github.com/crawlab-team/crawlab-vcs v0.1.0/go.mod h1:G6Hnt/3255QCGHO5Q0xJe1AbJE7m5t65E0v7flRJBJM= +github.com/crawlab-team/go-trace v0.1.0 h1:uCqfdqNfb+NwqdkQrBkcYfQ9iqGJ76MbPw1wK8n7xGg= +github.com/crawlab-team/go-trace v0.1.0/go.mod h1:LcWyn68HoT+d29CHM8L41pFHxsAcBMF1xjqJmWdyFh8= github.com/crawlab-team/goseaweedfs v0.1.6 h1:4Qmz75e65h4gbj0/sTM7pPVFwVJl8MihXf28igy2cFc= github.com/crawlab-team/goseaweedfs v0.1.6/go.mod h1:u+rwfqb0rnYllTLjCctE/z1Yp+TC8L+CbbWH8E2NstA= +github.com/crawlab-team/goseaweedfs v0.2.0 h1:9acRgmJVss+ghIqm/XMCNU0G2RUBAvvDaOOASvWNInc= +github.com/crawlab-team/goseaweedfs v0.2.0/go.mod h1:u+rwfqb0rnYllTLjCctE/z1Yp+TC8L+CbbWH8E2NstA= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -93,15 +123,22 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gamexg/proxyclient v0.0.0-20210207161252-499908056324/go.mod h1:Y1lsrg1lNY/7qdJ6masxXhIOUHajrlcixeMMWU59cjg= github.com/gavv/httpexpect/v2 v2.2.0 h1:0VwaEBmQaNFHX9x591A8Up+8shCwdF/nF0qlRd/nI48= github.com/gavv/httpexpect/v2 v2.2.0/go.mod h1:lnd0TqJLrP+wkJk3SFwtrpSlOAZQ7HaaIFuOYbgqgUM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= +github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= @@ -114,8 +151,20 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= -github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= @@ -156,6 +205,7 @@ github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGt github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -200,7 +250,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= @@ -244,6 +293,7 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imkira/go-interpol v1.0.0 h1:HrmLyvOLJyjR0YofMw8QGdCIuYOs4TJUBDNU5sJC09E= @@ -270,6 +320,7 @@ github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9 github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= @@ -291,6 +342,7 @@ github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzV github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -298,6 +350,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -307,12 +361,16 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/linxGnu/goseaweedfs v0.1.5/go.mod h1:Zwe/7H7FJaPQyMTNKXgv6fhVDw6qi34MMJQp1K0VLNc= github.com/linxGnu/gumble v1.0.0 h1:OAJud8Hy4rmV9I5p/KTRiVpwwklMTd9Ankza3Mz7a4M= github.com/linxGnu/gumble v1.0.0/go.mod h1:iyhNJpBHvJ0q2Hr41iiZRJyj6LLF47i2a9C9zLiucVY= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= @@ -324,7 +382,9 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= @@ -370,6 +430,7 @@ github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= @@ -397,8 +458,6 @@ github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E= github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -416,6 +475,7 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601/go.mod h1:mttDPaeLm87u74HMrP+n2tugXvIKWcwff/cqSX0lehY= github.com/shirou/gopsutil v3.20.11+incompatible h1:LJr4ZQK4mPpIV5gOa4jCOKOGb4ty4DZO54I4FGqIpto= github.com/shirou/gopsutil v3.20.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -450,10 +510,12 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -464,6 +526,10 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= +github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= +github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= +github.com/swaggo/swag v1.6.6/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= @@ -474,10 +540,16 @@ github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eN github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.9.0 h1:hNpmUdy/+ZXYpGy0OBfm7K0UQTzb73W0T0U4iJIVrMw= @@ -505,7 +577,6 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3Ifn github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -532,11 +603,12 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -556,11 +628,10 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -572,18 +643,21 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -593,8 +667,6 @@ golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -602,6 +674,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -615,19 +688,22 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg= -golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -636,8 +712,6 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -655,9 +729,13 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -665,13 +743,9 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -680,6 +754,7 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -693,8 +768,6 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d h1:HV9Z9qMhQEsdlvxNFELgQ11RkMzO3CMkjEySjCtuLes= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -711,7 +784,6 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= @@ -728,6 +800,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= @@ -735,6 +809,9 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/russross/blackfriday.v2 v2.0.0 h1:+FlnIV8DSQnT7NZ43hcVKcdJdzZoeCmJj4Ql8gq5keA= gopkg.in/russross/blackfriday.v2 v2.0.0/go.mod h1:6sSBNz/GtOm/pJTuh5UmBK2ZHfmnxGbl2NZg1UliSOI= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= From db7920ac6907895922349b558705f984fca9997f Mon Sep 17 00:00:00 2001 From: marvzhang Date: Thu, 15 Jul 2021 21:37:37 +0800 Subject: [PATCH 18/19] updated frontend --- frontend/.browserslistrc | 3 + frontend/.editorconfig | 37 +- frontend/.npmrc | 1 + frontend/Dockerfile | 23 - frontend/LICENSE | 42 +- frontend/babel.config.js | 3 +- frontend/jest.config.js | 29 - frontend/jest.config.ts | 194 + frontend/jsconfig.json | 9 - frontend/package-lock.json | 21097 ---------------- frontend/package.json | 110 +- frontend/postcss.config.js | 5 - frontend/public/favicon.ico | Bin 16958 -> 4286 bytes frontend/public/font-awesome.min.css | 4 - frontend/public/index.html | 163 +- frontend/sources.list | 4 - frontend/src/App.vue | 144 +- frontend/src/api/request.js | 31 - frontend/src/assets/404_images/404 2.png | Bin 98071 -> 0 bytes frontend/src/assets/404_images/404.png | Bin 98071 -> 0 bytes frontend/src/assets/404_images/404_cloud.png | Bin 4766 -> 0 bytes frontend/src/assets/js/loginCanvas.js | 262 + frontend/src/assets/logo.svg | 26 +- frontend/src/components/Breadcrumb/index.vue | 88 - .../Common/BatchAddScheduleDialog.vue | 315 - .../components/Common/BatchCrawlDialog.vue | 285 - .../components/Common/CrawlConfirmDialog.vue | 362 - .../components/Common/ParametersDialog.vue | 220 - frontend/src/components/Config/ConfigList.vue | 1259 - frontend/src/components/Cron/index.vue | 465 - frontend/src/components/Cron/language/cn.js | 61 - frontend/src/components/Cron/language/en.js | 71 - .../src/components/Cron/language/index.js | 7 - .../Documentation/Documentation.vue | 117 - .../Environment/EnvironmentList.vue | 81 - frontend/src/components/File/FileDetail.vue | 105 - frontend/src/components/File/FileEditor.vue | 823 + .../src/components/File/FileEditorNavMenu.vue | 479 + .../File/FileEditorNavMenuContextMenu.vue | 47 + .../src/components/File/FileEditorNavTabs.vue | 271 + .../File/FileEditorNavTabsContextMenu.vue | 43 + .../FileEditorNavTabsShowMoreContextMenu.vue | 54 + .../File/FileEditorSettingsDialog.vue | 198 + .../File/FileEditorSettingsFormItem.vue | 50 + frontend/src/components/File/FileList.vue | 679 - .../src/components/File/fileEditorDropZone.ts | 23 + frontend/src/components/Hamburger/index.vue | 43 - .../src/components/InfoView/NodeInfoView.vue | 75 - .../components/InfoView/SpiderInfoView.vue | 361 - .../src/components/InfoView/TaskInfoView.vue | 181 - .../components/Node/CreateEditNodeDialog.vue | 45 + frontend/src/components/Node/NodeActive.vue | 50 + frontend/src/components/Node/NodeForm.vue | 105 + .../src/components/Node/NodeInstallation.vue | 354 - .../Node/NodeInstallationMatrix.vue | 573 - frontend/src/components/Node/NodeNetwork.vue | 190 - frontend/src/components/Node/NodeRunners.vue | 99 + frontend/src/components/Node/NodeStatus.vue | 100 + frontend/src/components/Node/NodeType.vue | 55 + frontend/src/components/Node/node.ts | 61 + .../src/components/Overview/NodeOverview.vue | 50 - .../components/Overview/SpiderOverview.vue | 56 - .../src/components/Overview/TaskOverview.vue | 134 - frontend/src/components/Pagination/index.vue | 101 - frontend/src/components/PanThumb/index.vue | 140 - .../Schedule/CreateEditScheduleDialog.vue | 45 + .../src/components/Schedule/ScheduleCron.vue | 168 + .../src/components/Schedule/ScheduleForm.vue | 193 + .../components/Schedule/ScheduleTaskList.vue | 30 - frontend/src/components/Schedule/schedule.ts | 153 + .../src/components/Scrapy/SpiderScrapy.vue | 846 - frontend/src/components/Screenfull/index.vue | 51 - frontend/src/components/ScrollPane/index.vue | 81 - .../src/components/ScrollView/LogItem.vue | 121 - .../src/components/ScrollView/LogView.vue | 377 - .../src/components/Settings/GitSettings.vue | 480 - .../src/components/Share/dropdownMenu.vue | 100 - frontend/src/components/SizeSelect/index.vue | 55 - .../components/Spider/CopySpiderDialog.vue | 85 - .../Spider/CreateEditSpiderDialog.vue | 45 + .../src/components/Spider/RunSpiderDialog.vue | 186 + frontend/src/components/Spider/SpiderForm.vue | 198 + frontend/src/components/Spider/SpiderStat.vue | 100 + frontend/src/components/Spider/SpiderTag.vue | 38 + frontend/src/components/Spider/SpiderType.vue | 66 + frontend/src/components/Spider/spider.ts | 130 + frontend/src/components/Stats/MetricCard.vue | 89 - frontend/src/components/Stats/SpiderStats.vue | 197 - .../src/components/Status/StatusLegend.vue | 40 - frontend/src/components/Status/StatusTag.vue | 67 - frontend/src/components/Sticky/index.vue | 88 - frontend/src/components/SvgIcon/index.vue | 43 - .../components/TableView/DeployTableView.vue | 76 - .../components/TableView/FieldsTableView.vue | 360 - .../components/TableView/GeneralTableView.vue | 114 - .../TableView/SettingFieldsTableView.vue | 248 - .../components/TableView/TaskTableView.vue | 166 - frontend/src/components/ThemePicker/index.vue | 149 - .../Tinymce/components/editorImage 2.vue | 104 - .../Tinymce/components/editorImage.vue | 104 - frontend/src/components/Tinymce/index.vue | 210 - frontend/src/components/Tinymce/plugins.js | 7 - frontend/src/components/Tinymce/toolbar.js | 8 - frontend/src/components/UploadExcel/index.vue | 136 - frontend/src/components/button/Button.vue | 106 + .../src/components/button/FaIconButton.vue | 71 + frontend/src/components/button/IconButton.vue | 47 + .../src/components/button/LabelButton.vue | 50 + frontend/src/components/chart/LineChart.vue | 172 + frontend/src/components/chart/Metric.vue | 128 + frontend/src/components/chart/PieChart.vue | 137 + frontend/src/components/color/ColorPicker.vue | 74 + .../components/context-menu/ContextMenu.vue | 65 + .../context-menu/ContextMenuList.vue | 86 + .../src/components/dialog/ConfirmDialog.vue | 74 + .../dialog/CreateDialogContentBatch.vue | 105 + .../components/dialog/CreateEditDialog.vue | 151 + frontend/src/components/dialog/Dialog.vue | 93 + .../src/components/drag/DraggableItem.vue | 71 + .../components/drag/DraggableItemContent.vue | 21 + .../src/components/drag/DraggableList.vue | 111 + frontend/src/components/element/index.d.ts | 3 + frontend/src/components/empty/Empty.vue | 42 + frontend/src/components/empty/ImgEmpty.vue | 138 + .../src/components/filter/FilterCondition.vue | 164 + .../components/filter/FilterConditionList.vue | 68 + frontend/src/components/form/Form.vue | 90 + frontend/src/components/form/FormItem.vue | 209 + .../src/components/form/FormReadonlyValue.vue | 31 + frontend/src/components/form/FormTable.vue | 125 + .../src/components/form/FormTableField.vue | 239 + frontend/src/components/form/form.ts | 269 + frontend/src/components/form/formTable.ts | 67 + .../src/components/icon/AtomMaterialIcon.vue | 36 + frontend/src/components/icon/Icon.vue | 64 + frontend/src/components/icon/MenuItemIcon.vue | 51 + frontend/src/components/icon/icon.ts | 33 + .../src/components/input/InputWithButton.vue | 178 + frontend/src/components/input/TagInput.vue | 228 + .../src/components/input/TagInputItem.vue | 353 + frontend/src/components/nav/NavActionBack.vue | 65 + .../src/components/nav/NavActionButton.vue | 59 + .../src/components/nav/NavActionFaIcon.vue | 33 + .../src/components/nav/NavActionGroup.vue | 46 + .../nav/NavActionGroupDetailCommon.vue | 47 + frontend/src/components/nav/NavActionItem.vue | 78 + frontend/src/components/nav/NavActions.vue | 103 + frontend/src/components/nav/NavLink.vue | 66 + frontend/src/components/nav/NavSidebar.vue | 271 + frontend/src/components/nav/NavTabs.vue | 75 + .../project/CreateEditProjectDialog.vue | 45 + .../src/components/project/ProjectForm.vue | 50 + .../src/components/project/ProjectTag.vue | 33 + frontend/src/components/project/project.ts | 78 + frontend/src/components/switch/Switch.vue | 97 + frontend/src/components/tab/ActionTab.vue | 58 + frontend/src/components/tab/Tab.vue | 217 + frontend/src/components/table/Table.vue | 262 + .../src/components/table/TableActions.vue | 135 + frontend/src/components/table/TableCell.vue | 76 + .../components/table/TableColumnsTransfer.vue | 103 + frontend/src/components/table/TableHeader.vue | 284 + .../components/table/TableHeaderAction.vue | 86 + .../components/table/TableHeaderDialog.vue | 290 + .../table/TableHeaderDialogFilter.vue | 236 + .../table/TableHeaderDialogSort.vue | 101 + frontend/src/components/table/action.ts | 68 + frontend/src/components/table/column.ts | 136 + frontend/src/components/table/data.ts | 14 + frontend/src/components/table/header.ts | 16 + frontend/src/components/table/pagination.ts | 28 + frontend/src/components/table/store.ts | 22 + frontend/src/components/tag/CheckTag.vue | 108 + frontend/src/components/tag/CheckTagGroup.vue | 67 + .../components/tag/CreateEditTagDialog.vue | 44 + frontend/src/components/tag/LinkTag.vue | 53 + frontend/src/components/tag/Tag.vue | 197 + frontend/src/components/tag/TagForm.vue | 60 + frontend/src/components/tag/TagList.vue | 48 + frontend/src/components/tag/tag.ts | 71 + .../src/components/task/CreateTaskDialog.vue | 54 + frontend/src/components/task/TaskForm.vue | 314 + frontend/src/components/task/TaskMode.vue | 112 + frontend/src/components/task/TaskPriority.vue | 80 + frontend/src/components/task/TaskResults.vue | 93 + frontend/src/components/task/TaskStatus.vue | 120 + frontend/src/components/task/task.ts | 108 + frontend/src/components/time/Duration.vue | 37 + frontend/src/components/time/Time.vue | 48 + frontend/src/components/transfer/Transfer.vue | 193 + .../src/components/transfer/TransferPanel.vue | 203 + .../components/user/CreateEditUserDialog.vue | 45 + frontend/src/components/user/UserForm.vue | 98 + frontend/src/components/user/UserRole.vue | 54 + frontend/src/components/user/user.ts | 96 + frontend/src/constants/action.ts | 7 + frontend/src/constants/file.ts | 1 + frontend/src/constants/filter.ts | 13 + frontend/src/constants/form.ts | 9 + frontend/src/constants/keyboard.ts | 3 + frontend/src/constants/node.ts | 4 + frontend/src/constants/sort.ts | 3 + frontend/src/constants/spider.ts | 2 + frontend/src/constants/tab.ts | 8 + frontend/src/constants/table.ts | 4 + frontend/src/constants/task.ts | 11 + frontend/src/constants/transfer.ts | 0 frontend/src/constants/user.ts | 4 + frontend/src/i18n/index.js | 17 - frontend/src/i18n/index.ts | 14 + frontend/src/i18n/{en.js => lang/en.ts} | 10 +- frontend/src/i18n/{zh.js => lang/zh.ts} | 6 +- frontend/src/icons/index.js | 9 - frontend/src/icons/svg/example.svg | 1 - frontend/src/icons/svg/eye-open.svg | 1 - frontend/src/icons/svg/eye.svg | 1 - frontend/src/icons/svg/form.svg | 1 - frontend/src/icons/svg/link.svg | 1 - frontend/src/icons/svg/nested.svg | 1 - frontend/src/icons/svg/password.svg | 1 - frontend/src/icons/svg/table.svg | 1 - frontend/src/icons/svg/tree.svg | 1 - frontend/src/icons/svg/user.svg | 1 - frontend/src/icons/svgo.yml | 22 - frontend/src/interfaces/common/action.d.ts | 10 + frontend/src/interfaces/common/color.d.ts | 12 + .../interfaces/components/button/Button.d.ts | 12 + .../components/button/FaIconButton.d.ts | 3 + .../components/button/IconButton.d.ts | 3 + .../components/button/LabelButton.d.ts | 4 + .../interfaces/components/button/index.d.ts | 1 + .../components/chart/LineChart.d.ts | 9 + .../interfaces/components/chart/Metric.d.ts | 16 + .../interfaces/components/chart/PieChart.d.ts | 8 + .../components/color/ColorPicker.d.ts | 6 + .../components/context-menu/ContextMenu.d.ts | 9 + .../context-menu/ContextMenuList.d.ts | 3 + .../components/context-menu/index.d.ts | 5 + .../components/dialog/ConfirmDialog.d.ts | 4 + .../dialog/CreateDialogContentBatch.d.ts | 3 + .../components/dialog/CreateEditDialog.d.ts | 33 + .../interfaces/components/dialog/Dialog.d.ts | 15 + .../components/drag/DraggableItem.d.ts | 4 + .../components/drag/DraggableItemContent.d.ts | 5 + .../components/drag/DraggableList.d.ts | 18 + .../src/interfaces/components/drag/index.d.ts | 6 + .../components/file/FileEditor.d.ts | 5 + .../components/file/FileEditorNavMenu.d.ts | 12 + .../components/file/FileEditorNavTabs.d.ts | 5 + .../FileEditorNavTabsShowMoreContextMenu.d.ts | 9 + .../components/file/UseDropZone.d.ts | 19 + .../src/interfaces/components/file/index.d.ts | 44 + .../components/filter/FilterCondition.d.ts | 9 + .../filter/FilterConditionList.d.ts | 3 + .../interfaces/components/filter/index.d.ts | 12 + .../src/interfaces/components/form/Form.d.ts | 59 + .../interfaces/components/form/FormItem.d.ts | 16 + .../components/form/FormReadonlyValue.d.ts | 3 + .../interfaces/components/form/FormTable.d.ts | 15 + .../components/form/FormTableField.d.ts | 16 + .../components/icon/AtomMaterialIcon.ts | 4 + .../src/interfaces/components/icon/Icon.ts | 9 + .../components/icon/MenuItemIcon.d.ts | 4 + .../components/input/InputWithButton.d.ts | 9 + .../interfaces/components/input/TagInput.d.ts | 8 + .../components/input/TagInputItem.d.ts | 6 + .../interfaces/components/nav/NavAction.d.ts | 0 .../components/nav/NavActionBack.d.ts | 9 + .../interfaces/components/nav/NavActions.d.ts | 9 + .../interfaces/components/nav/NavLink.d.ts | 5 + .../interfaces/components/nav/NavSidebar.d.ts | 10 + .../interfaces/components/nav/NavTabs.d.ts | 0 .../src/interfaces/components/nav/index.d.ts | 10 + .../components/node/NodeActive.d.ts | 3 + .../components/node/NodeRunners.d.ts | 5 + .../components/node/NodeStatus.d.ts | 4 + .../interfaces/components/node/NodeType.d.ts | 4 + .../project/CreateProjectDialog.d.ts | 0 .../components/project/ProjectForm.d.ts | 0 .../components/project/ProjectTag.d.ts | 5 + .../components/schedule/ScheduleCron.d.ts | 4 + .../interfaces/components/select/index.d.ts | 4 + .../components/spider/CreateSpiderDialog.d.ts | 3 + .../components/spider/RunSpiderDialog.d.ts | 3 + .../components/spider/SpiderForm.d.ts | 3 + .../components/spider/SpiderStat.d.ts | 15 + .../components/spider/SpiderTag.d.ts | 3 + .../components/spider/SpiderType.d.ts | 9 + .../interfaces/components/switch/Switch.d.ts | 12 + .../interfaces/components/tab/ActionTab.d.ts | 4 + .../src/interfaces/components/tab/Tab.d.ts | 13 + .../interfaces/components/table/Table.d.ts | 106 + .../components/table/TableActions.d.ts | 21 + .../components/table/TableCell.d.ts | 5 + .../table/TableColumnsTransfer.d.ts | 5 + .../components/table/TableHeader.d.ts | 14 + .../components/table/TableHeaderAction.d.ts | 8 + .../components/table/TableHeaderDialog.d.ts | 12 + .../table/TableHeaderDialogFilter.d.ts | 11 + .../table/TableHeaderDialogSort.d.ts | 3 + .../interfaces/components/tag/CheckTag.d.ts | 3 + .../components/tag/CheckTagGroup.d.ts | 5 + .../interfaces/components/tag/LinkTag.d.ts | 3 + .../src/interfaces/components/tag/Tag.d.ts | 18 + .../interfaces/components/tag/TagList.d.ts | 4 + .../interfaces/components/task/TaskMode.d.ts | 3 + .../components/task/TaskPriority.d.ts | 3 + .../components/task/TaskResults.d.ts | 5 + .../components/task/TaskStatus.d.ts | 5 + .../interfaces/components/time/Duration.d.ts | 3 + .../src/interfaces/components/time/Time.d.ts | 4 + .../components/transfer/Transfer.d.ts | 15 + .../components/transfer/TransferPanel.d.ts | 9 + .../interfaces/components/user/UserRole.d.ts | 4 + frontend/src/interfaces/echarts.d.ts | 22 + frontend/src/interfaces/global.d.ts | 4 + frontend/src/interfaces/index.d.ts | 14 + .../src/interfaces/layout/BasicLayout.d.ts | 0 .../src/interfaces/layout/DetailLayout.d.ts | 5 + .../src/interfaces/layout/ListLayout.d.ts | 58 + .../interfaces/layout/components/Sidebar.d.ts | 6 + .../layout/components/TabsView.d.ts | 0 .../src/interfaces/models/dataCollection.d.ts | 3 + frontend/src/interfaces/models/index.d.ts | 6 + frontend/src/interfaces/models/node.d.ts | 14 + frontend/src/interfaces/models/project.d.ts | 4 + frontend/src/interfaces/models/result.d.ts | 7 + frontend/src/interfaces/models/spider.d.ts | 42 + frontend/src/interfaces/models/stats.d.ts | 12 + frontend/src/interfaces/models/tag.d.ts | 5 + frontend/src/interfaces/models/token.d.ts | 5 + frontend/src/interfaces/services/index.d.ts | 11 + frontend/src/interfaces/services/request.d.ts | 41 + frontend/src/interfaces/services/spider.d.ts | 12 + frontend/src/interfaces/store/index.d.ts | 165 + .../store/modules/dataCollection.d.ts | 25 + .../src/interfaces/store/modules/file.d.ts | 23 + .../src/interfaces/store/modules/layout.d.ts | 42 + .../src/interfaces/store/modules/login.d.ts | 3 + .../src/interfaces/store/modules/node.d.ts | 14 + .../src/interfaces/store/modules/project.d.ts | 18 + .../interfaces/store/modules/schedule.d.ts | 12 + .../src/interfaces/store/modules/spider.d.ts | 30 + .../src/interfaces/store/modules/tag.d.ts | 12 + .../src/interfaces/store/modules/task.d.ts | 43 + .../src/interfaces/store/modules/token.d.ts | 9 + .../src/interfaces/store/modules/user.d.ts | 11 + frontend/src/interfaces/views/dataSource.d.ts | 0 frontend/src/interfaces/views/login.d.ts | 12 + frontend/src/interfaces/views/node.d.ts | 0 frontend/src/interfaces/views/project.d.ts | 0 frontend/src/interfaces/views/result.d.ts | 4 + frontend/src/interfaces/views/schedule.d.ts | 14 + frontend/src/interfaces/views/spider.d.ts | 7 + frontend/src/interfaces/views/task.d.ts | 61 + frontend/src/interfaces/views/user.d.ts | 13 + frontend/src/layouts/BasicLayout.vue | 69 + frontend/src/layouts/DetailLayout.vue | 157 + frontend/src/layouts/ListLayout.vue | 250 + frontend/src/layouts/components/Header.vue | 82 + frontend/src/layouts/components/Sidebar.vue | 209 + frontend/src/layouts/components/TabsView.vue | 127 + frontend/src/layouts/detail.ts | 167 + frontend/src/layouts/list.ts | 131 + frontend/src/main.js | 88 - frontend/src/main.ts | 25 + frontend/src/permission.js | 42 - frontend/src/router/auth.ts | 21 + frontend/src/router/home.ts | 10 + frontend/src/router/index.js | 339 - frontend/src/router/index.ts | 53 + frontend/src/router/login.ts | 10 + frontend/src/router/node.ts | 28 + frontend/src/router/project.ts | 28 + frontend/src/router/schedule.ts | 26 + frontend/src/router/spider.ts | 49 + frontend/src/router/tag.ts | 24 + frontend/src/router/task.ts | 32 + frontend/src/router/token.ts | 10 + frontend/src/router/user.ts | 22 + frontend/src/services/index.ts | 45 + frontend/src/services/node/nodeService.ts | 14 + .../src/services/project/projectService.ts | 12 + frontend/src/services/request.ts | 127 + .../src/services/schedule/scheduleService.ts | 12 + frontend/src/services/spider/spiderService.ts | 64 + frontend/src/services/tag/tagService.ts | 12 + frontend/src/services/task/taskService.ts | 12 + frontend/src/services/token/tokenService.ts | 12 + frontend/src/services/user/userService.ts | 12 + frontend/src/shims-vue.d.ts | 6 + frontend/src/store/getters.js | 9 - frontend/src/store/index.js | 50 - frontend/src/store/index.ts | 30 + frontend/src/store/modules/app.js | 43 - frontend/src/store/modules/dataCollection.ts | 71 + frontend/src/store/modules/deploy.js | 32 - frontend/src/store/modules/dialogView.js | 19 - frontend/src/store/modules/doc.js | 61 - frontend/src/store/modules/file.js | 83 - frontend/src/store/modules/file.ts | 67 + frontend/src/store/modules/lang.js | 31 - frontend/src/store/modules/layout.ts | 89 + frontend/src/store/modules/login.ts | 10 + frontend/src/store/modules/node.js | 87 - frontend/src/store/modules/node.ts | 50 + frontend/src/store/modules/project.js | 60 - frontend/src/store/modules/project.ts | 60 + frontend/src/store/modules/schedule.js | 61 - frontend/src/store/modules/schedule.ts | 46 + frontend/src/store/modules/setting.js | 34 - frontend/src/store/modules/site.js | 96 - frontend/src/store/modules/spider.js | 362 - frontend/src/store/modules/spider.ts | 139 + frontend/src/store/modules/stats.js | 14 - frontend/src/store/modules/tag.ts | 30 + frontend/src/store/modules/tagsView.js | 161 - frontend/src/store/modules/task.js | 279 - frontend/src/store/modules/task.ts | 132 + frontend/src/store/modules/token.ts | 30 + frontend/src/store/modules/tour.js | 34 - frontend/src/store/modules/user.js | 183 - frontend/src/store/modules/user.ts | 38 + frontend/src/store/modules/version.js | 37 - frontend/src/styles/color.scss | 41 + frontend/src/styles/element-ui.scss | 8 + frontend/src/styles/index.scss | 15 + frontend/src/styles/sidebar.scss | 26 +- frontend/src/styles/variables.scss | 166 +- frontend/src/test/views/home/Home.spec.ts | 0 frontend/src/test/views/login/Login.spec.ts | 1 + frontend/src/utils/array.ts | 4 + frontend/src/utils/auth.js | 13 - frontend/src/utils/auth.ts | 9 + frontend/src/utils/auto.ts | 11 + frontend/src/utils/codemirror.ts | 309 + frontend/src/utils/color.ts | 5 + frontend/src/utils/debounce.ts | 28 + frontend/src/utils/doc.js | 28 - frontend/src/utils/encrypt.js | 13 - frontend/src/utils/form.ts | 10 + frontend/src/utils/func.ts | 11 + frontend/src/utils/hash.ts | 5 + frontend/src/utils/html.js | 16 - frontend/src/utils/i18n.js | 12 - frontend/src/utils/index.js | 15 - frontend/src/utils/list.ts | 28 + frontend/src/utils/log.js | 11 - frontend/src/utils/mongo.ts | 5 + frontend/src/utils/object.ts | 8 + frontend/src/utils/pagination.ts | 6 + frontend/src/utils/path.ts | 8 + frontend/src/utils/request.js | 123 - frontend/src/utils/result.ts | 12 + frontend/src/utils/route.ts | 6 + frontend/src/utils/scrapy.js | 212 - frontend/src/utils/service.ts | 23 + frontend/src/utils/sleep.ts | 3 + frontend/src/utils/stats.js | 29 - frontend/src/utils/stats.ts | 28 + frontend/src/utils/store.ts | 263 + frontend/src/utils/string.ts | 6 + frontend/src/utils/table.ts | 129 + frontend/src/utils/task.ts | 49 + frontend/src/utils/tour.js | 71 - frontend/src/utils/validate.js | 15 - frontend/src/utils/validate.ts | 11 + frontend/src/views/404.vue | 228 - .../src/views/challenge/ChallengeList.vue | 197 - frontend/src/views/data/list/ResultList.vue | 108 + frontend/src/views/doc/Disclaimer.vue | 92 - frontend/src/views/feedback/Feedback.vue | 175 - frontend/src/views/home/Home.vue | 496 +- frontend/src/views/layout/Layout.vue | 163 - .../src/views/layout/components/AppMain.vue | 29 - .../src/views/layout/components/Navbar.vue | 324 - .../views/layout/components/Sidebar/Item.vue | 34 - .../views/layout/components/Sidebar/Link.vue | 35 - .../layout/components/Sidebar/SidebarItem.vue | 115 - .../views/layout/components/Sidebar/index.vue | 99 - .../src/views/layout/components/TagsView.vue | 302 - frontend/src/views/layout/components/index.js | 4 - .../src/views/layout/mixin/ResizeHandler.js | 41 - frontend/src/views/login/Login.vue | 425 + frontend/src/views/login/index.vue | 543 - frontend/src/views/node/NodeDetail.vue | 165 - frontend/src/views/node/NodeList.vue | 417 - frontend/src/views/node/detail/NodeDetail.vue | 21 + .../detail/tabs/NodeDetailTabOverview.vue | 24 + .../node/detail/tabs/NodeDetailTabTasks.vue | 56 + frontend/src/views/node/list/NodeList.vue | 41 + frontend/src/views/node/list/nodeList.ts | 230 + frontend/src/views/project/ProjectList.vue | 338 - .../views/project/detail/ProjectDetail.vue | 21 + .../detail/tabs/ProjectDetailTabOverview.vue | 24 + .../detail/tabs/ProjectDetailTabSpiders.vue | 50 + .../src/views/project/list/ProjectList.vue | 55 + .../src/views/project/list/projectList.ts | 149 + frontend/src/views/repo/RepoList.vue | 292 - frontend/src/views/schedule/ScheduleList.vue | 892 - .../views/schedule/detail/ScheduleDetail.vue | 24 + .../views/schedule/detail/scheduleDetail.ts | 19 + .../detail/tabs/ScheduleDetailTabOverview.vue | 24 + .../detail/tabs/ScheduleDetailTabTasks.vue | 56 + .../src/views/schedule/list/ScheduleList.vue | 62 + .../src/views/schedule/list/scheduleList.ts | 217 + frontend/src/views/setting/Setting.vue | 602 - frontend/src/views/site/SiteList.vue | 433 - frontend/src/views/spider/SpiderDetail.vue | 306 - frontend/src/views/spider/SpiderList.vue | 1510 -- frontend/src/views/spider/SpiderSchedules.vue | 58 - .../src/views/spider/detail/SpiderDetail.vue | 31 + .../actions/SpiderDetailActionsCommon.vue | 67 + .../actions/SpiderDetailActionsFiles.vue | 73 + .../src/views/spider/detail/spiderDetail.ts | 46 + .../detail/tabs/SpiderDetailTabData.vue | 69 + .../detail/tabs/SpiderDetailTabFiles.vue | 205 + .../detail/tabs/SpiderDetailTabOverview.vue | 26 + .../detail/tabs/SpiderDetailTabSchedules.vue | 51 + .../detail/tabs/SpiderDetailTabSettings.vue | 22 + .../detail/tabs/SpiderDetailTabTasks.vue | 51 + frontend/src/views/spider/list/SpiderList.vue | 79 + frontend/src/views/spider/list/spiderList.ts | 275 + frontend/src/views/tag/detail/TagDetail.vue | 21 + .../tag/detail/tabs/TagDetailTabOverview.vue | 24 + frontend/src/views/tag/list/TagList.vue | 65 + frontend/src/views/tag/list/tagList.ts | 92 + frontend/src/views/task/TaskDetail.vue | 294 - frontend/src/views/task/TaskList.vue | 672 - frontend/src/views/task/detail/TaskDetail.vue | 34 + .../actions/TaskDetailActionsCommon.vue | 107 + .../detail/actions/TaskDetailActionsLogs.vue | 69 + .../task/detail/tabs/TaskDetailTabData.vue | 93 + .../task/detail/tabs/TaskDetailTabLogs.vue | 162 + .../detail/tabs/TaskDetailTabOverview.vue | 24 + frontend/src/views/task/detail/taskDetail.ts | 108 + frontend/src/views/task/list/TaskList.vue | 48 + frontend/src/views/task/list/taskList.ts | 301 + frontend/src/views/token/list/TokenList.vue | 45 + frontend/src/views/token/list/tokenList.ts | 128 + frontend/src/views/user/UserList.vue | 281 - frontend/src/views/user/detail/UserDetail.vue | 24 + .../detail/tabs/UserDetailTabOverview.vue | 24 + frontend/src/views/user/detail/userDetail.ts | 9 + frontend/src/views/user/list/UserList.vue | 65 + frontend/src/views/user/list/userList.ts | 132 + frontend/static/favicon.ico | Bin 1150 -> 0 bytes frontend/tsconfig.json | 40 + frontend/vue.config.js | 34 - frontend/yarn.lock | 8388 +++--- 550 files changed, 27134 insertions(+), 49444 deletions(-) create mode 100644 frontend/.browserslistrc create mode 100644 frontend/.npmrc delete mode 100644 frontend/Dockerfile delete mode 100644 frontend/jest.config.js create mode 100644 frontend/jest.config.ts delete mode 100644 frontend/jsconfig.json delete mode 100644 frontend/package-lock.json delete mode 100644 frontend/postcss.config.js delete mode 100644 frontend/public/font-awesome.min.css delete mode 100644 frontend/sources.list delete mode 100644 frontend/src/api/request.js delete mode 100644 frontend/src/assets/404_images/404 2.png delete mode 100644 frontend/src/assets/404_images/404.png delete mode 100644 frontend/src/assets/404_images/404_cloud.png create mode 100644 frontend/src/assets/js/loginCanvas.js delete mode 100644 frontend/src/components/Breadcrumb/index.vue delete mode 100644 frontend/src/components/Common/BatchAddScheduleDialog.vue delete mode 100644 frontend/src/components/Common/BatchCrawlDialog.vue delete mode 100644 frontend/src/components/Common/CrawlConfirmDialog.vue delete mode 100644 frontend/src/components/Common/ParametersDialog.vue delete mode 100644 frontend/src/components/Config/ConfigList.vue delete mode 100644 frontend/src/components/Cron/index.vue delete mode 100644 frontend/src/components/Cron/language/cn.js delete mode 100644 frontend/src/components/Cron/language/en.js delete mode 100644 frontend/src/components/Cron/language/index.js delete mode 100644 frontend/src/components/Documentation/Documentation.vue delete mode 100644 frontend/src/components/Environment/EnvironmentList.vue delete mode 100644 frontend/src/components/File/FileDetail.vue create mode 100644 frontend/src/components/File/FileEditor.vue create mode 100644 frontend/src/components/File/FileEditorNavMenu.vue create mode 100644 frontend/src/components/File/FileEditorNavMenuContextMenu.vue create mode 100644 frontend/src/components/File/FileEditorNavTabs.vue create mode 100644 frontend/src/components/File/FileEditorNavTabsContextMenu.vue create mode 100644 frontend/src/components/File/FileEditorNavTabsShowMoreContextMenu.vue create mode 100644 frontend/src/components/File/FileEditorSettingsDialog.vue create mode 100644 frontend/src/components/File/FileEditorSettingsFormItem.vue delete mode 100644 frontend/src/components/File/FileList.vue create mode 100644 frontend/src/components/File/fileEditorDropZone.ts delete mode 100644 frontend/src/components/Hamburger/index.vue delete mode 100644 frontend/src/components/InfoView/NodeInfoView.vue delete mode 100644 frontend/src/components/InfoView/SpiderInfoView.vue delete mode 100644 frontend/src/components/InfoView/TaskInfoView.vue create mode 100644 frontend/src/components/Node/CreateEditNodeDialog.vue create mode 100644 frontend/src/components/Node/NodeActive.vue create mode 100644 frontend/src/components/Node/NodeForm.vue delete mode 100644 frontend/src/components/Node/NodeInstallation.vue delete mode 100644 frontend/src/components/Node/NodeInstallationMatrix.vue delete mode 100644 frontend/src/components/Node/NodeNetwork.vue create mode 100644 frontend/src/components/Node/NodeRunners.vue create mode 100644 frontend/src/components/Node/NodeStatus.vue create mode 100644 frontend/src/components/Node/NodeType.vue create mode 100644 frontend/src/components/Node/node.ts delete mode 100644 frontend/src/components/Overview/NodeOverview.vue delete mode 100644 frontend/src/components/Overview/SpiderOverview.vue delete mode 100644 frontend/src/components/Overview/TaskOverview.vue delete mode 100644 frontend/src/components/Pagination/index.vue delete mode 100644 frontend/src/components/PanThumb/index.vue create mode 100644 frontend/src/components/Schedule/CreateEditScheduleDialog.vue create mode 100644 frontend/src/components/Schedule/ScheduleCron.vue create mode 100644 frontend/src/components/Schedule/ScheduleForm.vue delete mode 100644 frontend/src/components/Schedule/ScheduleTaskList.vue create mode 100644 frontend/src/components/Schedule/schedule.ts delete mode 100644 frontend/src/components/Scrapy/SpiderScrapy.vue delete mode 100644 frontend/src/components/Screenfull/index.vue delete mode 100644 frontend/src/components/ScrollPane/index.vue delete mode 100644 frontend/src/components/ScrollView/LogItem.vue delete mode 100644 frontend/src/components/ScrollView/LogView.vue delete mode 100644 frontend/src/components/Settings/GitSettings.vue delete mode 100644 frontend/src/components/Share/dropdownMenu.vue delete mode 100644 frontend/src/components/SizeSelect/index.vue delete mode 100644 frontend/src/components/Spider/CopySpiderDialog.vue create mode 100644 frontend/src/components/Spider/CreateEditSpiderDialog.vue create mode 100644 frontend/src/components/Spider/RunSpiderDialog.vue create mode 100644 frontend/src/components/Spider/SpiderForm.vue create mode 100644 frontend/src/components/Spider/SpiderStat.vue create mode 100644 frontend/src/components/Spider/SpiderTag.vue create mode 100644 frontend/src/components/Spider/SpiderType.vue create mode 100644 frontend/src/components/Spider/spider.ts delete mode 100644 frontend/src/components/Stats/MetricCard.vue delete mode 100644 frontend/src/components/Stats/SpiderStats.vue delete mode 100644 frontend/src/components/Status/StatusLegend.vue delete mode 100644 frontend/src/components/Status/StatusTag.vue delete mode 100644 frontend/src/components/Sticky/index.vue delete mode 100644 frontend/src/components/SvgIcon/index.vue delete mode 100644 frontend/src/components/TableView/DeployTableView.vue delete mode 100644 frontend/src/components/TableView/FieldsTableView.vue delete mode 100644 frontend/src/components/TableView/GeneralTableView.vue delete mode 100644 frontend/src/components/TableView/SettingFieldsTableView.vue delete mode 100644 frontend/src/components/TableView/TaskTableView.vue delete mode 100644 frontend/src/components/ThemePicker/index.vue delete mode 100644 frontend/src/components/Tinymce/components/editorImage 2.vue delete mode 100644 frontend/src/components/Tinymce/components/editorImage.vue delete mode 100644 frontend/src/components/Tinymce/index.vue delete mode 100644 frontend/src/components/Tinymce/plugins.js delete mode 100644 frontend/src/components/Tinymce/toolbar.js delete mode 100644 frontend/src/components/UploadExcel/index.vue create mode 100644 frontend/src/components/button/Button.vue create mode 100644 frontend/src/components/button/FaIconButton.vue create mode 100644 frontend/src/components/button/IconButton.vue create mode 100644 frontend/src/components/button/LabelButton.vue create mode 100644 frontend/src/components/chart/LineChart.vue create mode 100644 frontend/src/components/chart/Metric.vue create mode 100644 frontend/src/components/chart/PieChart.vue create mode 100644 frontend/src/components/color/ColorPicker.vue create mode 100644 frontend/src/components/context-menu/ContextMenu.vue create mode 100644 frontend/src/components/context-menu/ContextMenuList.vue create mode 100644 frontend/src/components/dialog/ConfirmDialog.vue create mode 100644 frontend/src/components/dialog/CreateDialogContentBatch.vue create mode 100644 frontend/src/components/dialog/CreateEditDialog.vue create mode 100644 frontend/src/components/dialog/Dialog.vue create mode 100644 frontend/src/components/drag/DraggableItem.vue create mode 100644 frontend/src/components/drag/DraggableItemContent.vue create mode 100644 frontend/src/components/drag/DraggableList.vue create mode 100644 frontend/src/components/element/index.d.ts create mode 100644 frontend/src/components/empty/Empty.vue create mode 100644 frontend/src/components/empty/ImgEmpty.vue create mode 100644 frontend/src/components/filter/FilterCondition.vue create mode 100644 frontend/src/components/filter/FilterConditionList.vue create mode 100644 frontend/src/components/form/Form.vue create mode 100644 frontend/src/components/form/FormItem.vue create mode 100644 frontend/src/components/form/FormReadonlyValue.vue create mode 100644 frontend/src/components/form/FormTable.vue create mode 100644 frontend/src/components/form/FormTableField.vue create mode 100644 frontend/src/components/form/form.ts create mode 100644 frontend/src/components/form/formTable.ts create mode 100644 frontend/src/components/icon/AtomMaterialIcon.vue create mode 100644 frontend/src/components/icon/Icon.vue create mode 100644 frontend/src/components/icon/MenuItemIcon.vue create mode 100644 frontend/src/components/icon/icon.ts create mode 100644 frontend/src/components/input/InputWithButton.vue create mode 100644 frontend/src/components/input/TagInput.vue create mode 100644 frontend/src/components/input/TagInputItem.vue create mode 100644 frontend/src/components/nav/NavActionBack.vue create mode 100644 frontend/src/components/nav/NavActionButton.vue create mode 100644 frontend/src/components/nav/NavActionFaIcon.vue create mode 100644 frontend/src/components/nav/NavActionGroup.vue create mode 100644 frontend/src/components/nav/NavActionGroupDetailCommon.vue create mode 100644 frontend/src/components/nav/NavActionItem.vue create mode 100644 frontend/src/components/nav/NavActions.vue create mode 100644 frontend/src/components/nav/NavLink.vue create mode 100644 frontend/src/components/nav/NavSidebar.vue create mode 100644 frontend/src/components/nav/NavTabs.vue create mode 100644 frontend/src/components/project/CreateEditProjectDialog.vue create mode 100644 frontend/src/components/project/ProjectForm.vue create mode 100644 frontend/src/components/project/ProjectTag.vue create mode 100644 frontend/src/components/project/project.ts create mode 100644 frontend/src/components/switch/Switch.vue create mode 100644 frontend/src/components/tab/ActionTab.vue create mode 100644 frontend/src/components/tab/Tab.vue create mode 100644 frontend/src/components/table/Table.vue create mode 100644 frontend/src/components/table/TableActions.vue create mode 100644 frontend/src/components/table/TableCell.vue create mode 100644 frontend/src/components/table/TableColumnsTransfer.vue create mode 100644 frontend/src/components/table/TableHeader.vue create mode 100644 frontend/src/components/table/TableHeaderAction.vue create mode 100644 frontend/src/components/table/TableHeaderDialog.vue create mode 100644 frontend/src/components/table/TableHeaderDialogFilter.vue create mode 100644 frontend/src/components/table/TableHeaderDialogSort.vue create mode 100644 frontend/src/components/table/action.ts create mode 100644 frontend/src/components/table/column.ts create mode 100644 frontend/src/components/table/data.ts create mode 100644 frontend/src/components/table/header.ts create mode 100644 frontend/src/components/table/pagination.ts create mode 100644 frontend/src/components/table/store.ts create mode 100644 frontend/src/components/tag/CheckTag.vue create mode 100644 frontend/src/components/tag/CheckTagGroup.vue create mode 100644 frontend/src/components/tag/CreateEditTagDialog.vue create mode 100644 frontend/src/components/tag/LinkTag.vue create mode 100644 frontend/src/components/tag/Tag.vue create mode 100644 frontend/src/components/tag/TagForm.vue create mode 100644 frontend/src/components/tag/TagList.vue create mode 100644 frontend/src/components/tag/tag.ts create mode 100644 frontend/src/components/task/CreateTaskDialog.vue create mode 100644 frontend/src/components/task/TaskForm.vue create mode 100644 frontend/src/components/task/TaskMode.vue create mode 100644 frontend/src/components/task/TaskPriority.vue create mode 100644 frontend/src/components/task/TaskResults.vue create mode 100644 frontend/src/components/task/TaskStatus.vue create mode 100644 frontend/src/components/task/task.ts create mode 100644 frontend/src/components/time/Duration.vue create mode 100644 frontend/src/components/time/Time.vue create mode 100644 frontend/src/components/transfer/Transfer.vue create mode 100644 frontend/src/components/transfer/TransferPanel.vue create mode 100644 frontend/src/components/user/CreateEditUserDialog.vue create mode 100644 frontend/src/components/user/UserForm.vue create mode 100644 frontend/src/components/user/UserRole.vue create mode 100644 frontend/src/components/user/user.ts create mode 100644 frontend/src/constants/action.ts create mode 100644 frontend/src/constants/file.ts create mode 100644 frontend/src/constants/filter.ts create mode 100644 frontend/src/constants/form.ts create mode 100644 frontend/src/constants/keyboard.ts create mode 100644 frontend/src/constants/node.ts create mode 100644 frontend/src/constants/sort.ts create mode 100644 frontend/src/constants/spider.ts create mode 100644 frontend/src/constants/tab.ts create mode 100644 frontend/src/constants/table.ts create mode 100644 frontend/src/constants/task.ts create mode 100644 frontend/src/constants/transfer.ts create mode 100644 frontend/src/constants/user.ts delete mode 100644 frontend/src/i18n/index.js create mode 100644 frontend/src/i18n/index.ts rename frontend/src/i18n/{en.js => lang/en.ts} (62%) rename frontend/src/i18n/{zh.js => lang/zh.ts} (99%) delete mode 100644 frontend/src/icons/index.js delete mode 100644 frontend/src/icons/svg/example.svg delete mode 100644 frontend/src/icons/svg/eye-open.svg delete mode 100644 frontend/src/icons/svg/eye.svg delete mode 100644 frontend/src/icons/svg/form.svg delete mode 100644 frontend/src/icons/svg/link.svg delete mode 100644 frontend/src/icons/svg/nested.svg delete mode 100644 frontend/src/icons/svg/password.svg delete mode 100644 frontend/src/icons/svg/table.svg delete mode 100644 frontend/src/icons/svg/tree.svg delete mode 100644 frontend/src/icons/svg/user.svg delete mode 100644 frontend/src/icons/svgo.yml create mode 100644 frontend/src/interfaces/common/action.d.ts create mode 100644 frontend/src/interfaces/common/color.d.ts create mode 100644 frontend/src/interfaces/components/button/Button.d.ts create mode 100644 frontend/src/interfaces/components/button/FaIconButton.d.ts create mode 100644 frontend/src/interfaces/components/button/IconButton.d.ts create mode 100644 frontend/src/interfaces/components/button/LabelButton.d.ts create mode 100644 frontend/src/interfaces/components/button/index.d.ts create mode 100644 frontend/src/interfaces/components/chart/LineChart.d.ts create mode 100644 frontend/src/interfaces/components/chart/Metric.d.ts create mode 100644 frontend/src/interfaces/components/chart/PieChart.d.ts create mode 100644 frontend/src/interfaces/components/color/ColorPicker.d.ts create mode 100644 frontend/src/interfaces/components/context-menu/ContextMenu.d.ts create mode 100644 frontend/src/interfaces/components/context-menu/ContextMenuList.d.ts create mode 100644 frontend/src/interfaces/components/context-menu/index.d.ts create mode 100644 frontend/src/interfaces/components/dialog/ConfirmDialog.d.ts create mode 100644 frontend/src/interfaces/components/dialog/CreateDialogContentBatch.d.ts create mode 100644 frontend/src/interfaces/components/dialog/CreateEditDialog.d.ts create mode 100644 frontend/src/interfaces/components/dialog/Dialog.d.ts create mode 100644 frontend/src/interfaces/components/drag/DraggableItem.d.ts create mode 100644 frontend/src/interfaces/components/drag/DraggableItemContent.d.ts create mode 100644 frontend/src/interfaces/components/drag/DraggableList.d.ts create mode 100644 frontend/src/interfaces/components/drag/index.d.ts create mode 100644 frontend/src/interfaces/components/file/FileEditor.d.ts create mode 100644 frontend/src/interfaces/components/file/FileEditorNavMenu.d.ts create mode 100644 frontend/src/interfaces/components/file/FileEditorNavTabs.d.ts create mode 100644 frontend/src/interfaces/components/file/FileEditorNavTabsShowMoreContextMenu.d.ts create mode 100644 frontend/src/interfaces/components/file/UseDropZone.d.ts create mode 100644 frontend/src/interfaces/components/file/index.d.ts create mode 100644 frontend/src/interfaces/components/filter/FilterCondition.d.ts create mode 100644 frontend/src/interfaces/components/filter/FilterConditionList.d.ts create mode 100644 frontend/src/interfaces/components/filter/index.d.ts create mode 100644 frontend/src/interfaces/components/form/Form.d.ts create mode 100644 frontend/src/interfaces/components/form/FormItem.d.ts create mode 100644 frontend/src/interfaces/components/form/FormReadonlyValue.d.ts create mode 100644 frontend/src/interfaces/components/form/FormTable.d.ts create mode 100644 frontend/src/interfaces/components/form/FormTableField.d.ts create mode 100644 frontend/src/interfaces/components/icon/AtomMaterialIcon.ts create mode 100644 frontend/src/interfaces/components/icon/Icon.ts create mode 100644 frontend/src/interfaces/components/icon/MenuItemIcon.d.ts create mode 100644 frontend/src/interfaces/components/input/InputWithButton.d.ts create mode 100644 frontend/src/interfaces/components/input/TagInput.d.ts create mode 100644 frontend/src/interfaces/components/input/TagInputItem.d.ts create mode 100644 frontend/src/interfaces/components/nav/NavAction.d.ts create mode 100644 frontend/src/interfaces/components/nav/NavActionBack.d.ts create mode 100644 frontend/src/interfaces/components/nav/NavActions.d.ts create mode 100644 frontend/src/interfaces/components/nav/NavLink.d.ts create mode 100644 frontend/src/interfaces/components/nav/NavSidebar.d.ts create mode 100644 frontend/src/interfaces/components/nav/NavTabs.d.ts create mode 100644 frontend/src/interfaces/components/nav/index.d.ts create mode 100644 frontend/src/interfaces/components/node/NodeActive.d.ts create mode 100644 frontend/src/interfaces/components/node/NodeRunners.d.ts create mode 100644 frontend/src/interfaces/components/node/NodeStatus.d.ts create mode 100644 frontend/src/interfaces/components/node/NodeType.d.ts create mode 100644 frontend/src/interfaces/components/project/CreateProjectDialog.d.ts create mode 100644 frontend/src/interfaces/components/project/ProjectForm.d.ts create mode 100644 frontend/src/interfaces/components/project/ProjectTag.d.ts create mode 100644 frontend/src/interfaces/components/schedule/ScheduleCron.d.ts create mode 100644 frontend/src/interfaces/components/select/index.d.ts create mode 100644 frontend/src/interfaces/components/spider/CreateSpiderDialog.d.ts create mode 100644 frontend/src/interfaces/components/spider/RunSpiderDialog.d.ts create mode 100644 frontend/src/interfaces/components/spider/SpiderForm.d.ts create mode 100644 frontend/src/interfaces/components/spider/SpiderStat.d.ts create mode 100644 frontend/src/interfaces/components/spider/SpiderTag.d.ts create mode 100644 frontend/src/interfaces/components/spider/SpiderType.d.ts create mode 100644 frontend/src/interfaces/components/switch/Switch.d.ts create mode 100644 frontend/src/interfaces/components/tab/ActionTab.d.ts create mode 100644 frontend/src/interfaces/components/tab/Tab.d.ts create mode 100644 frontend/src/interfaces/components/table/Table.d.ts create mode 100644 frontend/src/interfaces/components/table/TableActions.d.ts create mode 100644 frontend/src/interfaces/components/table/TableCell.d.ts create mode 100644 frontend/src/interfaces/components/table/TableColumnsTransfer.d.ts create mode 100644 frontend/src/interfaces/components/table/TableHeader.d.ts create mode 100644 frontend/src/interfaces/components/table/TableHeaderAction.d.ts create mode 100644 frontend/src/interfaces/components/table/TableHeaderDialog.d.ts create mode 100644 frontend/src/interfaces/components/table/TableHeaderDialogFilter.d.ts create mode 100644 frontend/src/interfaces/components/table/TableHeaderDialogSort.d.ts create mode 100644 frontend/src/interfaces/components/tag/CheckTag.d.ts create mode 100644 frontend/src/interfaces/components/tag/CheckTagGroup.d.ts create mode 100644 frontend/src/interfaces/components/tag/LinkTag.d.ts create mode 100644 frontend/src/interfaces/components/tag/Tag.d.ts create mode 100644 frontend/src/interfaces/components/tag/TagList.d.ts create mode 100644 frontend/src/interfaces/components/task/TaskMode.d.ts create mode 100644 frontend/src/interfaces/components/task/TaskPriority.d.ts create mode 100644 frontend/src/interfaces/components/task/TaskResults.d.ts create mode 100644 frontend/src/interfaces/components/task/TaskStatus.d.ts create mode 100644 frontend/src/interfaces/components/time/Duration.d.ts create mode 100644 frontend/src/interfaces/components/time/Time.d.ts create mode 100644 frontend/src/interfaces/components/transfer/Transfer.d.ts create mode 100644 frontend/src/interfaces/components/transfer/TransferPanel.d.ts create mode 100644 frontend/src/interfaces/components/user/UserRole.d.ts create mode 100644 frontend/src/interfaces/echarts.d.ts create mode 100644 frontend/src/interfaces/global.d.ts create mode 100644 frontend/src/interfaces/index.d.ts create mode 100644 frontend/src/interfaces/layout/BasicLayout.d.ts create mode 100644 frontend/src/interfaces/layout/DetailLayout.d.ts create mode 100644 frontend/src/interfaces/layout/ListLayout.d.ts create mode 100644 frontend/src/interfaces/layout/components/Sidebar.d.ts create mode 100644 frontend/src/interfaces/layout/components/TabsView.d.ts create mode 100644 frontend/src/interfaces/models/dataCollection.d.ts create mode 100644 frontend/src/interfaces/models/index.d.ts create mode 100644 frontend/src/interfaces/models/node.d.ts create mode 100644 frontend/src/interfaces/models/project.d.ts create mode 100644 frontend/src/interfaces/models/result.d.ts create mode 100644 frontend/src/interfaces/models/spider.d.ts create mode 100644 frontend/src/interfaces/models/stats.d.ts create mode 100644 frontend/src/interfaces/models/tag.d.ts create mode 100644 frontend/src/interfaces/models/token.d.ts create mode 100644 frontend/src/interfaces/services/index.d.ts create mode 100644 frontend/src/interfaces/services/request.d.ts create mode 100644 frontend/src/interfaces/services/spider.d.ts create mode 100644 frontend/src/interfaces/store/index.d.ts create mode 100644 frontend/src/interfaces/store/modules/dataCollection.d.ts create mode 100644 frontend/src/interfaces/store/modules/file.d.ts create mode 100644 frontend/src/interfaces/store/modules/layout.d.ts create mode 100644 frontend/src/interfaces/store/modules/login.d.ts create mode 100644 frontend/src/interfaces/store/modules/node.d.ts create mode 100644 frontend/src/interfaces/store/modules/project.d.ts create mode 100644 frontend/src/interfaces/store/modules/schedule.d.ts create mode 100644 frontend/src/interfaces/store/modules/spider.d.ts create mode 100644 frontend/src/interfaces/store/modules/tag.d.ts create mode 100644 frontend/src/interfaces/store/modules/task.d.ts create mode 100644 frontend/src/interfaces/store/modules/token.d.ts create mode 100644 frontend/src/interfaces/store/modules/user.d.ts create mode 100644 frontend/src/interfaces/views/dataSource.d.ts create mode 100644 frontend/src/interfaces/views/login.d.ts create mode 100644 frontend/src/interfaces/views/node.d.ts create mode 100644 frontend/src/interfaces/views/project.d.ts create mode 100644 frontend/src/interfaces/views/result.d.ts create mode 100644 frontend/src/interfaces/views/schedule.d.ts create mode 100644 frontend/src/interfaces/views/spider.d.ts create mode 100644 frontend/src/interfaces/views/task.d.ts create mode 100644 frontend/src/interfaces/views/user.d.ts create mode 100644 frontend/src/layouts/BasicLayout.vue create mode 100644 frontend/src/layouts/DetailLayout.vue create mode 100644 frontend/src/layouts/ListLayout.vue create mode 100644 frontend/src/layouts/components/Header.vue create mode 100644 frontend/src/layouts/components/Sidebar.vue create mode 100644 frontend/src/layouts/components/TabsView.vue create mode 100644 frontend/src/layouts/detail.ts create mode 100644 frontend/src/layouts/list.ts delete mode 100644 frontend/src/main.js create mode 100644 frontend/src/main.ts delete mode 100644 frontend/src/permission.js create mode 100644 frontend/src/router/auth.ts create mode 100644 frontend/src/router/home.ts delete mode 100644 frontend/src/router/index.js create mode 100644 frontend/src/router/index.ts create mode 100644 frontend/src/router/login.ts create mode 100644 frontend/src/router/node.ts create mode 100644 frontend/src/router/project.ts create mode 100644 frontend/src/router/schedule.ts create mode 100644 frontend/src/router/spider.ts create mode 100644 frontend/src/router/tag.ts create mode 100644 frontend/src/router/task.ts create mode 100644 frontend/src/router/token.ts create mode 100644 frontend/src/router/user.ts create mode 100644 frontend/src/services/index.ts create mode 100644 frontend/src/services/node/nodeService.ts create mode 100644 frontend/src/services/project/projectService.ts create mode 100644 frontend/src/services/request.ts create mode 100644 frontend/src/services/schedule/scheduleService.ts create mode 100644 frontend/src/services/spider/spiderService.ts create mode 100644 frontend/src/services/tag/tagService.ts create mode 100644 frontend/src/services/task/taskService.ts create mode 100644 frontend/src/services/token/tokenService.ts create mode 100644 frontend/src/services/user/userService.ts create mode 100644 frontend/src/shims-vue.d.ts delete mode 100644 frontend/src/store/getters.js delete mode 100644 frontend/src/store/index.js create mode 100644 frontend/src/store/index.ts delete mode 100644 frontend/src/store/modules/app.js create mode 100644 frontend/src/store/modules/dataCollection.ts delete mode 100644 frontend/src/store/modules/deploy.js delete mode 100644 frontend/src/store/modules/dialogView.js delete mode 100644 frontend/src/store/modules/doc.js delete mode 100644 frontend/src/store/modules/file.js create mode 100644 frontend/src/store/modules/file.ts delete mode 100644 frontend/src/store/modules/lang.js create mode 100644 frontend/src/store/modules/layout.ts create mode 100644 frontend/src/store/modules/login.ts delete mode 100644 frontend/src/store/modules/node.js create mode 100644 frontend/src/store/modules/node.ts delete mode 100644 frontend/src/store/modules/project.js create mode 100644 frontend/src/store/modules/project.ts delete mode 100644 frontend/src/store/modules/schedule.js create mode 100644 frontend/src/store/modules/schedule.ts delete mode 100644 frontend/src/store/modules/setting.js delete mode 100644 frontend/src/store/modules/site.js delete mode 100644 frontend/src/store/modules/spider.js create mode 100644 frontend/src/store/modules/spider.ts delete mode 100644 frontend/src/store/modules/stats.js create mode 100644 frontend/src/store/modules/tag.ts delete mode 100644 frontend/src/store/modules/tagsView.js delete mode 100644 frontend/src/store/modules/task.js create mode 100644 frontend/src/store/modules/task.ts create mode 100644 frontend/src/store/modules/token.ts delete mode 100644 frontend/src/store/modules/tour.js delete mode 100644 frontend/src/store/modules/user.js create mode 100644 frontend/src/store/modules/user.ts delete mode 100644 frontend/src/store/modules/version.js create mode 100644 frontend/src/styles/color.scss create mode 100644 frontend/src/test/views/home/Home.spec.ts create mode 100644 frontend/src/test/views/login/Login.spec.ts create mode 100644 frontend/src/utils/array.ts delete mode 100644 frontend/src/utils/auth.js create mode 100644 frontend/src/utils/auth.ts create mode 100644 frontend/src/utils/auto.ts create mode 100644 frontend/src/utils/codemirror.ts create mode 100644 frontend/src/utils/color.ts create mode 100644 frontend/src/utils/debounce.ts delete mode 100644 frontend/src/utils/doc.js delete mode 100644 frontend/src/utils/encrypt.js create mode 100644 frontend/src/utils/form.ts create mode 100644 frontend/src/utils/func.ts create mode 100644 frontend/src/utils/hash.ts delete mode 100644 frontend/src/utils/html.js delete mode 100644 frontend/src/utils/i18n.js delete mode 100644 frontend/src/utils/index.js create mode 100644 frontend/src/utils/list.ts delete mode 100644 frontend/src/utils/log.js create mode 100644 frontend/src/utils/mongo.ts create mode 100644 frontend/src/utils/object.ts create mode 100644 frontend/src/utils/pagination.ts create mode 100644 frontend/src/utils/path.ts delete mode 100644 frontend/src/utils/request.js create mode 100644 frontend/src/utils/result.ts create mode 100644 frontend/src/utils/route.ts delete mode 100644 frontend/src/utils/scrapy.js create mode 100644 frontend/src/utils/service.ts create mode 100644 frontend/src/utils/sleep.ts delete mode 100644 frontend/src/utils/stats.js create mode 100644 frontend/src/utils/stats.ts create mode 100644 frontend/src/utils/store.ts create mode 100644 frontend/src/utils/string.ts create mode 100644 frontend/src/utils/table.ts create mode 100644 frontend/src/utils/task.ts delete mode 100644 frontend/src/utils/tour.js delete mode 100644 frontend/src/utils/validate.js create mode 100644 frontend/src/utils/validate.ts delete mode 100644 frontend/src/views/404.vue delete mode 100644 frontend/src/views/challenge/ChallengeList.vue create mode 100644 frontend/src/views/data/list/ResultList.vue delete mode 100644 frontend/src/views/doc/Disclaimer.vue delete mode 100644 frontend/src/views/feedback/Feedback.vue delete mode 100644 frontend/src/views/layout/Layout.vue delete mode 100644 frontend/src/views/layout/components/AppMain.vue delete mode 100644 frontend/src/views/layout/components/Navbar.vue delete mode 100644 frontend/src/views/layout/components/Sidebar/Item.vue delete mode 100644 frontend/src/views/layout/components/Sidebar/Link.vue delete mode 100644 frontend/src/views/layout/components/Sidebar/SidebarItem.vue delete mode 100644 frontend/src/views/layout/components/Sidebar/index.vue delete mode 100644 frontend/src/views/layout/components/TagsView.vue delete mode 100644 frontend/src/views/layout/components/index.js delete mode 100644 frontend/src/views/layout/mixin/ResizeHandler.js create mode 100644 frontend/src/views/login/Login.vue delete mode 100644 frontend/src/views/login/index.vue delete mode 100644 frontend/src/views/node/NodeDetail.vue delete mode 100644 frontend/src/views/node/NodeList.vue create mode 100644 frontend/src/views/node/detail/NodeDetail.vue create mode 100644 frontend/src/views/node/detail/tabs/NodeDetailTabOverview.vue create mode 100644 frontend/src/views/node/detail/tabs/NodeDetailTabTasks.vue create mode 100644 frontend/src/views/node/list/NodeList.vue create mode 100644 frontend/src/views/node/list/nodeList.ts delete mode 100644 frontend/src/views/project/ProjectList.vue create mode 100644 frontend/src/views/project/detail/ProjectDetail.vue create mode 100644 frontend/src/views/project/detail/tabs/ProjectDetailTabOverview.vue create mode 100644 frontend/src/views/project/detail/tabs/ProjectDetailTabSpiders.vue create mode 100644 frontend/src/views/project/list/ProjectList.vue create mode 100644 frontend/src/views/project/list/projectList.ts delete mode 100644 frontend/src/views/repo/RepoList.vue delete mode 100644 frontend/src/views/schedule/ScheduleList.vue create mode 100644 frontend/src/views/schedule/detail/ScheduleDetail.vue create mode 100644 frontend/src/views/schedule/detail/scheduleDetail.ts create mode 100644 frontend/src/views/schedule/detail/tabs/ScheduleDetailTabOverview.vue create mode 100644 frontend/src/views/schedule/detail/tabs/ScheduleDetailTabTasks.vue create mode 100644 frontend/src/views/schedule/list/ScheduleList.vue create mode 100644 frontend/src/views/schedule/list/scheduleList.ts delete mode 100644 frontend/src/views/setting/Setting.vue delete mode 100644 frontend/src/views/site/SiteList.vue delete mode 100644 frontend/src/views/spider/SpiderDetail.vue delete mode 100644 frontend/src/views/spider/SpiderList.vue delete mode 100644 frontend/src/views/spider/SpiderSchedules.vue create mode 100644 frontend/src/views/spider/detail/SpiderDetail.vue create mode 100644 frontend/src/views/spider/detail/actions/SpiderDetailActionsCommon.vue create mode 100644 frontend/src/views/spider/detail/actions/SpiderDetailActionsFiles.vue create mode 100644 frontend/src/views/spider/detail/spiderDetail.ts create mode 100644 frontend/src/views/spider/detail/tabs/SpiderDetailTabData.vue create mode 100644 frontend/src/views/spider/detail/tabs/SpiderDetailTabFiles.vue create mode 100644 frontend/src/views/spider/detail/tabs/SpiderDetailTabOverview.vue create mode 100644 frontend/src/views/spider/detail/tabs/SpiderDetailTabSchedules.vue create mode 100644 frontend/src/views/spider/detail/tabs/SpiderDetailTabSettings.vue create mode 100644 frontend/src/views/spider/detail/tabs/SpiderDetailTabTasks.vue create mode 100644 frontend/src/views/spider/list/SpiderList.vue create mode 100644 frontend/src/views/spider/list/spiderList.ts create mode 100644 frontend/src/views/tag/detail/TagDetail.vue create mode 100644 frontend/src/views/tag/detail/tabs/TagDetailTabOverview.vue create mode 100644 frontend/src/views/tag/list/TagList.vue create mode 100644 frontend/src/views/tag/list/tagList.ts delete mode 100644 frontend/src/views/task/TaskDetail.vue delete mode 100644 frontend/src/views/task/TaskList.vue create mode 100644 frontend/src/views/task/detail/TaskDetail.vue create mode 100644 frontend/src/views/task/detail/actions/TaskDetailActionsCommon.vue create mode 100644 frontend/src/views/task/detail/actions/TaskDetailActionsLogs.vue create mode 100644 frontend/src/views/task/detail/tabs/TaskDetailTabData.vue create mode 100644 frontend/src/views/task/detail/tabs/TaskDetailTabLogs.vue create mode 100644 frontend/src/views/task/detail/tabs/TaskDetailTabOverview.vue create mode 100644 frontend/src/views/task/detail/taskDetail.ts create mode 100644 frontend/src/views/task/list/TaskList.vue create mode 100644 frontend/src/views/task/list/taskList.ts create mode 100644 frontend/src/views/token/list/TokenList.vue create mode 100644 frontend/src/views/token/list/tokenList.ts delete mode 100644 frontend/src/views/user/UserList.vue create mode 100644 frontend/src/views/user/detail/UserDetail.vue create mode 100644 frontend/src/views/user/detail/tabs/UserDetailTabOverview.vue create mode 100644 frontend/src/views/user/detail/userDetail.ts create mode 100644 frontend/src/views/user/list/UserList.vue create mode 100644 frontend/src/views/user/list/userList.ts delete mode 100644 frontend/static/favicon.ico create mode 100644 frontend/tsconfig.json delete mode 100644 frontend/vue.config.js diff --git a/frontend/.browserslistrc b/frontend/.browserslistrc new file mode 100644 index 00000000..214388fe --- /dev/null +++ b/frontend/.browserslistrc @@ -0,0 +1,3 @@ +> 1% +last 2 versions +not dead diff --git a/frontend/.editorconfig b/frontend/.editorconfig index a20656db..6fb90ce6 100644 --- a/frontend/.editorconfig +++ b/frontend/.editorconfig @@ -1,13 +1,32 @@ root = true [*] -charset = utf-8 -indent_style = space -indent_size = 2 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true +# charset = utf-8 +# end_of_line = lf +# indent_size = 4 +# indent_style = space +# insert_final_newline = true +# max_line_length = 120 +# tab_width = 4 +# trim_trailing_whitespace = true -[*.md] -insert_final_newline = false -trim_trailing_whitespace = false \ No newline at end of file +[*.scss] +# indent_size = 2 + +[{*.ats, *.ts}] +# indent_size = 2 +# tab_width = 2 + +[{*.js, *.cjs}] +# indent_size = 2 +# tab_width = 2 + +[{*.sht, *.html, *.shtm, *.shtml, *.htm, *.ng}] +# indent_size = 2 +# tab_width = 2 + +[{.analysis_options, *.yml, *.yaml}] +# indent_size = 2 + +[{.babelrc, .prettierrc, .stylelintrc, .eslintrc, jest.config, *.json, *.jsb3, *.jsb2, *.bowerrc}] +# indent_size = 2 diff --git a/frontend/.npmrc b/frontend/.npmrc new file mode 100644 index 00000000..ae444623 --- /dev/null +++ b/frontend/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npm.taobao.org diff --git a/frontend/Dockerfile b/frontend/Dockerfile deleted file mode 100644 index 52ecb549..00000000 --- a/frontend/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM node:8.16.0-alpine AS frontend-build - -ADD . /app -WORKDIR /app - -# install frontend -RUN npm install -g yarn \ - && yarn install --registry=https://registry.npm.taobao.org - -RUN npm run build:prod - -FROM alpine - -#RUN apk update -RUN apk add nginx -COPY --from=frontend-build /app/dist /app/dist -COPY --from=frontend-build /app/conf/crawlab.conf /etc/nginx/conf.d -#RUN nginx -s start -#COPY ./dist /usr/share/nginx/html - -#EXPOSE 80 -#EXPOSE 8080 - diff --git a/frontend/LICENSE b/frontend/LICENSE index 61515750..e41311d2 100644 --- a/frontend/LICENSE +++ b/frontend/LICENSE @@ -1,21 +1,29 @@ -MIT License +BSD 3-Clause License -Copyright (c) 2017-present PanJiaChen +Copyright (c) 2020, Crawlab Team +All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/frontend/babel.config.js b/frontend/babel.config.js index e9558405..ce6ed5cf 100644 --- a/frontend/babel.config.js +++ b/frontend/babel.config.js @@ -1,5 +1,6 @@ module.exports = { presets: [ - '@vue/cli-plugin-babel/preset' + '@vue/cli-plugin-babel/preset', + '@babel/preset-typescript' ] } diff --git a/frontend/jest.config.js b/frontend/jest.config.js deleted file mode 100644 index 2707cd47..00000000 --- a/frontend/jest.config.js +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = { - moduleFileExtensions: [ - 'js', - 'jsx', - 'json', - 'vue' - ], - - transform: { - '^.+\\.vue$': 'vue-jest', - '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', - '^.+\\.jsx?$': 'babel-jest' - }, - - moduleNameMapper: { - '^@/(.*)$': '/src/$1' - }, - - snapshotSerializers: [ - 'jest-serializer-vue' - ], - - testMatch: [ - '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' - ], - - testURL: 'http://localhost/', - preset: '@vue/cli-plugin-unit-jest' -} diff --git a/frontend/jest.config.ts b/frontend/jest.config.ts new file mode 100644 index 00000000..1ceea513 --- /dev/null +++ b/frontend/jest.config.ts @@ -0,0 +1,194 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/en/configuration.html + */ + +export default { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/private/var/folders/r0/jl9gx1m97tb2qpggj961z3n40000gn/T/jest_dx", + + // Automatically clear mock calls and instances between every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: 'coverage', + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'v8', + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "json", + // "jsx", + // "ts", + // "tsx", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: undefined, + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state between every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state between every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: 'node', + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jasmine2", + + // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href + // testURL: "http://localhost", + + // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" + // timers: "real", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; diff --git a/frontend/jsconfig.json b/frontend/jsconfig.json deleted file mode 100644 index adc48451..00000000 --- a/frontend/jsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "./", - "paths": { - "@/*": ["src/*"] - } - }, - "exclude": ["node_modules", "dist"] -} diff --git a/frontend/package-lock.json b/frontend/package-lock.json deleted file mode 100644 index 78eb92fb..00000000 --- a/frontend/package-lock.json +++ /dev/null @@ -1,21097 +0,0 @@ -{ - "name": "crawlab", - "version": "0.4.10", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.1.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.1.tgz", - "integrity": "sha1-1UgcUJXaocV+FuVMb5GYRDr7Sf8=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.1" - } - }, - "@babel/compat-data": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/compat-data/download/@babel/compat-data-7.10.5.tgz?cache=0&sync_timestamp=1594750677870&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcompat-data%2Fdownload%2F%40babel%2Fcompat-data-7.10.5.tgz", - "integrity": "sha1-04Ql5n6paxSAo/UEBNG/hWdjAaY=", - "dev": true, - "requires": { - "browserslist": "^4.12.0", - "invariant": "^2.2.4", - "semver": "^5.5.0" - } - }, - "@babel/core": { - "version": "7.10.2", - "resolved": "https://registry.npm.taobao.org/@babel/core/download/@babel/core-7.10.2.tgz?cache=0&sync_timestamp=1594750765166&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcore%2Fdownload%2F%40babel%2Fcore-7.10.2.tgz", - "integrity": "sha1-vWeGBGZoqSWsK9L9lbV5uSojs2o=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/generator": "^7.10.2", - "@babel/helper-module-transforms": "^7.10.1", - "@babel/helpers": "^7.10.1", - "@babel/parser": "^7.10.2", - "@babel/template": "^7.10.1", - "@babel/traverse": "^7.10.1", - "@babel/types": "^7.10.2", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/json5/download/json5-2.1.3.tgz", - "integrity": "sha1-ybD3+pIzv+WAf+ZvzzpWF+1ZfUM=", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.10.2", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.2.tgz", - "integrity": "sha1-D6W1sjiduL/fzDSStVHuIPXdaak=", - "dev": true, - "requires": { - "@babel/types": "^7.10.2", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-annotate-as-pure/download/@babel/helper-annotate-as-pure-7.10.4.tgz", - "integrity": "sha1-W/DUlaP3V6w72ki1vzs7ownHK6M=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-builder-binary-assignment-operator-visitor/download/@babel/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz?cache=0&sync_timestamp=1593522841395&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-builder-binary-assignment-operator-visitor%2Fdownload%2F%40babel%2Fhelper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha1-uwt18xv5jL+f8UPBrleLhydK4aM=", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-compilation-targets/download/@babel/helper-compilation-targets-7.10.4.tgz?cache=0&sync_timestamp=1593521085687&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-compilation-targets%2Fdownload%2F%40babel%2Fhelper-compilation-targets-7.10.4.tgz", - "integrity": "sha1-gEro4/BDdmB8x5G51H1UAnYzK9I=", - "dev": true, - "requires": { - "@babel/compat-data": "^7.10.4", - "browserslist": "^4.12.0", - "invariant": "^2.2.4", - "levenary": "^1.1.1", - "semver": "^5.5.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-create-class-features-plugin/download/@babel/helper-create-class-features-plugin-7.10.5.tgz", - "integrity": "sha1-n2FEa6gOgkCwpchcb9rIRZ1vJZ0=", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.10.5", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.10.5.tgz", - "integrity": "sha1-Fy9W56Y+eBEvOgQFXyQ2WvcC5+4=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.10.4.tgz?cache=0&sync_timestamp=1593522827576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha1-UNyWQT1ZT5lad5BZBbBYk813lnM=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.10.4.tgz", - "integrity": "sha1-1YXNk4jqBuYDHkzUS2cTy+rZ5s8=", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-create-regexp-features-plugin/download/@babel/helper-create-regexp-features-plugin-7.10.4.tgz?cache=0&sync_timestamp=1593522952175&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-create-regexp-features-plugin%2Fdownload%2F%40babel%2Fhelper-create-regexp-features-plugin-7.10.4.tgz", - "integrity": "sha1-/dYNiFJGWaC2lZwFeZJeQlcU87g=", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-regex": "^7.10.4", - "regexpu-core": "^4.7.0" - } - }, - "@babel/helper-define-map": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-define-map/download/@babel/helper-define-map-7.10.5.tgz?cache=0&sync_timestamp=1594750707541&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-define-map%2Fdownload%2F%40babel%2Fhelper-define-map-7.10.5.tgz", - "integrity": "sha1-tTwQ23imQIABUmkrEzkxR6y5uzA=", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-explode-assignable-expression/download/@babel/helper-explode-assignable-expression-7.10.4.tgz?cache=0&sync_timestamp=1593522841702&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-explode-assignable-expression%2Fdownload%2F%40babel%2Fhelper-explode-assignable-expression-7.10.4.tgz", - "integrity": "sha1-QKHNkXv/Eoj2malKdbN6Gi29jHw=", - "dev": true, - "requires": { - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.1.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.1.tgz", - "integrity": "sha1-kr1jgpv8khWsqdne+oX1a1OUVPQ=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.1", - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.1.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.1.tgz", - "integrity": "sha1-cwM5CoG6fLWWE4laGSuThQ43P30=", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-hoist-variables/download/@babel/helper-hoist-variables-7.10.4.tgz?cache=0&sync_timestamp=1593521259807&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-hoist-variables%2Fdownload%2F%40babel%2Fhelper-hoist-variables-7.10.4.tgz", - "integrity": "sha1-1JsAHR1aaMpeZgTdoBpil/fJOB4=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.10.1.tgz", - "integrity": "sha1-Qyln/X4SpK/vZsRofUyiK8BFbxU=", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-module-imports": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.10.1.tgz?cache=0&sync_timestamp=1593522826853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.10.1.tgz", - "integrity": "sha1-3TMb1FvMxWbOdwBOnQX+F63ROHY=", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-module-transforms": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.10.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-transforms%2Fdownload%2F%40babel%2Fhelper-module-transforms-7.10.1.tgz", - "integrity": "sha1-JOLwjuaDLGCxV7sJNshr73IQxiI=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.1", - "@babel/helper-replace-supers": "^7.10.1", - "@babel/helper-simple-access": "^7.10.1", - "@babel/helper-split-export-declaration": "^7.10.1", - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1", - "lodash": "^4.17.13" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.10.1.tgz?cache=0&sync_timestamp=1593522827576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.10.1.tgz", - "integrity": "sha1-tKHyVhhwzhJHzt2wKjhg+pbXJUM=", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.1.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.1.tgz", - "integrity": "sha1-7Fpc8O7JJbZsYFgDKLEiwBIwoSc=", - "dev": true - }, - "@babel/helper-regex": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-regex/download/@babel/helper-regex-7.10.5.tgz?cache=0&sync_timestamp=1594750677873&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-regex%2Fdownload%2F%40babel%2Fhelper-regex-7.10.5.tgz", - "integrity": "sha1-Mt+7eYmQc8QVVXBToZvQVarlCuA=", - "dev": true, - "requires": { - "lodash": "^4.17.19" - }, - "dependencies": { - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-remap-async-to-generator/download/@babel/helper-remap-async-to-generator-7.10.4.tgz?cache=0&sync_timestamp=1593521228698&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-remap-async-to-generator%2Fdownload%2F%40babel%2Fhelper-remap-async-to-generator-7.10.4.tgz", - "integrity": "sha1-/Oi+pOlpC76SMFbe0h5UtOi2jtU=", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-replace-supers": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.10.1.tgz", - "integrity": "sha1-7GhZ0gxdgIf2otxOAU23Iol18T0=", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.1", - "@babel/helper-optimise-call-expression": "^7.10.1", - "@babel/traverse": "^7.10.1", - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-simple-access": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-simple-access/download/@babel/helper-simple-access-7.10.1.tgz?cache=0&sync_timestamp=1593521217867&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-simple-access%2Fdownload%2F%40babel%2Fhelper-simple-access-7.10.1.tgz", - "integrity": "sha1-CPt+Iqzp64Mm9+OSChwgUvE9hR4=", - "dev": true, - "requires": { - "@babel/template": "^7.10.1", - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.1.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.1.tgz", - "integrity": "sha1-xvS+HLwV46ho5MZKF9XTHXVNo18=", - "dev": true, - "requires": { - "@babel/types": "^7.10.1" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha1-p4x6clHgH2FlEtMbEK3PUq2l4NI=", - "dev": true - }, - "@babel/helper-wrap-function": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-wrap-function/download/@babel/helper-wrap-function-7.10.4.tgz?cache=0&sync_timestamp=1593522949000&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-wrap-function%2Fdownload%2F%40babel%2Fhelper-wrap-function-7.10.4.tgz", - "integrity": "sha1-im9wHqsP8592W1oc/vQJmQ5iS4c=", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helpers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helpers/download/@babel/helpers-7.10.4.tgz", - "integrity": "sha1-Kr6w1yGv98Cpc3a54fb2XXpHUEQ=", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.10.4.tgz", - "integrity": "sha1-fRvf1ldTU4+r5sOFls23bZrGAUM=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.10.2", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.2.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.2.tgz", - "integrity": "sha1-hxgH8QRCuS/5fkeDubVPagyoEtA=", - "dev": true - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-async-generator-functions/download/@babel/plugin-proposal-async-generator-functions-7.10.5.tgz?cache=0&sync_timestamp=1594750682516&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-async-generator-functions%2Fdownload%2F%40babel%2Fplugin-proposal-async-generator-functions-7.10.5.tgz", - "integrity": "sha1-NJHKvy98F5q4IGBs7Cf+0V4OhVg=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4", - "@babel/plugin-syntax-async-generators": "^7.8.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-class-properties/download/@babel/plugin-proposal-class-properties-7.10.4.tgz", - "integrity": "sha1-ozv2Mto5ClnHqMVwBF0RFc13iAc=", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-decorators": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-decorators/download/@babel/plugin-proposal-decorators-7.10.5.tgz?cache=0&sync_timestamp=1594750722573&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-decorators%2Fdownload%2F%40babel%2Fplugin-proposal-decorators-7.10.5.tgz", - "integrity": "sha1-QomLukeLxLGuJCpwOpU6etNQ/7Q=", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-decorators": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-dynamic-import/download/@babel/plugin-proposal-dynamic-import-7.10.4.tgz?cache=0&sync_timestamp=1593521117836&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-dynamic-import%2Fdownload%2F%40babel%2Fplugin-proposal-dynamic-import-7.10.4.tgz", - "integrity": "sha1-uleibLmLN3QenVvKG4sN34KR8X4=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-json-strings/download/@babel/plugin-proposal-json-strings-7.10.4.tgz?cache=0&sync_timestamp=1593521117237&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-json-strings%2Fdownload%2F%40babel%2Fplugin-proposal-json-strings-7.10.4.tgz", - "integrity": "sha1-WT5ZxjUoFgIzvTIbGuvgggwjQds=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-nullish-coalescing-operator/download/@babel/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz?cache=0&sync_timestamp=1593521118939&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-nullish-coalescing-operator%2Fdownload%2F%40babel%2Fplugin-proposal-nullish-coalescing-operator-7.10.4.tgz", - "integrity": "sha1-AqfpYfwy5tWy2wZJ4Bv4Dd7n4Eo=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-numeric-separator/download/@babel/plugin-proposal-numeric-separator-7.10.4.tgz", - "integrity": "sha1-zhWQ/wplrRKXCmCdeIVemkwa7wY=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-object-rest-spread/download/@babel/plugin-proposal-object-rest-spread-7.10.4.tgz", - "integrity": "sha1-UBKawha5pqVbOFP92SPnS/VTpMA=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-optional-catch-binding/download/@babel/plugin-proposal-optional-catch-binding-7.10.4.tgz", - "integrity": "sha1-Mck4MJ0kp4pJ1o/av/qoY3WFVN0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-optional-chaining/download/@babel/plugin-proposal-optional-chaining-7.10.4.tgz?cache=0&sync_timestamp=1593521121830&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-optional-chaining%2Fdownload%2F%40babel%2Fplugin-proposal-optional-chaining-7.10.4.tgz", - "integrity": "sha1-dQ8SVekwofgtjN3kUDH4Gg0K3/c=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-private-methods/download/@babel/plugin-proposal-private-methods-7.10.4.tgz?cache=0&sync_timestamp=1593521235156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-proposal-private-methods%2Fdownload%2F%40babel%2Fplugin-proposal-private-methods-7.10.4.tgz", - "integrity": "sha1-sWDZcrj9ulx9ERoUX8jEIfwqaQk=", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-proposal-unicode-property-regex/download/@babel/plugin-proposal-unicode-property-regex-7.10.4.tgz", - "integrity": "sha1-RIPNpTBBzjQTt/4vAAImZd36p10=", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-async-generators/download/@babel/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha1-qYP7Gusuw/btBCohD2QOkOeG/g0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-bigint/download/@babel/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha1-TJpvZp9dDN8bkKFnHpoUa+UwDOo=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-class-properties/download/@babel/plugin-syntax-class-properties-7.10.4.tgz?cache=0&sync_timestamp=1593522957421&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-class-properties%2Fdownload%2F%40babel%2Fplugin-syntax-class-properties-7.10.4.tgz", - "integrity": "sha1-ZkTmoLqlWmH54yMfbJ7rbuRsEkw=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-syntax-decorators": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-decorators/download/@babel/plugin-syntax-decorators-7.10.4.tgz?cache=0&sync_timestamp=1593521120720&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-decorators%2Fdownload%2F%40babel%2Fplugin-syntax-decorators-7.10.4.tgz", - "integrity": "sha1-aFMIWyxCn50yLQL1pjUBjN6yNgw=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-dynamic-import/download/@babel/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha1-Yr+Ysto80h1iYVT8lu5bPLaOrLM=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-import-meta/download/@babel/plugin-syntax-import-meta-7.10.4.tgz?cache=0&sync_timestamp=1593523074996&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-import-meta%2Fdownload%2F%40babel%2Fplugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha1-7mATSMNw+jNNIge+FYd3SWUh/VE=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-json-strings/download/@babel/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha1-AcohtmjNghjJ5kDLbdiMVBKyyWo=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-jsx/download/@babel/plugin-syntax-jsx-7.10.4.tgz?cache=0&sync_timestamp=1593522939386&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-jsx%2Fdownload%2F%40babel%2Fplugin-syntax-jsx-7.10.4.tgz", - "integrity": "sha1-Oauq48v3EMQ3PYQpSE5rohNAFmw=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-logical-assignment-operators/download/@babel/plugin-syntax-logical-assignment-operators-7.10.4.tgz?cache=0&sync_timestamp=1593521259188&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-logical-assignment-operators%2Fdownload%2F%40babel%2Fplugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha1-ypHvRjA1MESLkGZSusLp/plB9pk=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-nullish-coalescing-operator/download/@babel/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha1-Fn7XA2iIYIH3S1w2xlqIwDtm0ak=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-numeric-separator/download/@babel/plugin-syntax-numeric-separator-7.10.4.tgz?cache=0&sync_timestamp=1593521768131&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-syntax-numeric-separator%2Fdownload%2F%40babel%2Fplugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha1-ubBws+M1cM2f0Hun+pHA3Te5r5c=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-object-rest-spread/download/@babel/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha1-YOIl7cvZimQDMqLnLdPmbxr1WHE=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-optional-catch-binding/download/@babel/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha1-YRGiZbz7Ag6579D9/X0mQCue1sE=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-optional-chaining/download/@babel/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha1-T2nCq5UWfgGAzVM2YT+MV4j31Io=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-syntax-top-level-await/download/@babel/plugin-syntax-top-level-await-7.10.4.tgz", - "integrity": "sha1-S764kXtU/PdoNk4KgfVg4zo+9X0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-arrow-functions/download/@babel/plugin-transform-arrow-functions-7.10.4.tgz?cache=0&sync_timestamp=1593522807583&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-arrow-functions%2Fdownload%2F%40babel%2Fplugin-transform-arrow-functions-7.10.4.tgz", - "integrity": "sha1-4ilg135pfHT0HFAdRNc9v4pqZM0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-async-to-generator/download/@babel/plugin-transform-async-to-generator-7.10.4.tgz?cache=0&sync_timestamp=1593522851748&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-async-to-generator%2Fdownload%2F%40babel%2Fplugin-transform-async-to-generator-7.10.4.tgz", - "integrity": "sha1-QaUBfknrbzzak5KlHu8pQFskWjc=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4" - }, - "dependencies": { - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.10.4.tgz?cache=0&sync_timestamp=1593522826853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.10.4.tgz", - "integrity": "sha1-TFxUvgS9MWcKc4J5fXW5+i5bViA=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-block-scoped-functions/download/@babel/plugin-transform-block-scoped-functions-7.10.4.tgz?cache=0&sync_timestamp=1593521910347&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-block-scoped-functions%2Fdownload%2F%40babel%2Fplugin-transform-block-scoped-functions-7.10.4.tgz", - "integrity": "sha1-GvpZV0T3XkOpGvc7DZmOz+Trwug=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-block-scoping/download/@babel/plugin-transform-block-scoping-7.10.5.tgz?cache=0&sync_timestamp=1594750687483&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-block-scoping%2Fdownload%2F%40babel%2Fplugin-transform-block-scoping-7.10.5.tgz", - "integrity": "sha1-uBuKr++/5o8PZffvOXuezmimA30=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-classes": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-classes/download/@babel/plugin-transform-classes-7.10.4.tgz", - "integrity": "sha1-QFE2rys+IYvEoZJiKLyRerGgrcc=", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-define-map": "^7.10.4", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "globals": "^11.1.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.10.5.tgz", - "integrity": "sha1-Fy9W56Y+eBEvOgQFXyQ2WvcC5+4=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.10.4.tgz?cache=0&sync_timestamp=1593522827576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha1-UNyWQT1ZT5lad5BZBbBYk813lnM=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.10.4.tgz", - "integrity": "sha1-1YXNk4jqBuYDHkzUS2cTy+rZ5s8=", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-computed-properties/download/@babel/plugin-transform-computed-properties-7.10.4.tgz?cache=0&sync_timestamp=1593522921161&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-computed-properties%2Fdownload%2F%40babel%2Fplugin-transform-computed-properties-7.10.4.tgz", - "integrity": "sha1-ne2DqBboLe0o1S1LTsvdgQzfwOs=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-destructuring/download/@babel/plugin-transform-destructuring-7.10.4.tgz", - "integrity": "sha1-cN3Ss9G+qD0BUJ6bsl3bOnT8heU=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-dotall-regex/download/@babel/plugin-transform-dotall-regex-7.10.4.tgz", - "integrity": "sha1-RpwgYhBcHragQOr0+sS0iAeDle4=", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-duplicate-keys/download/@babel/plugin-transform-duplicate-keys-7.10.4.tgz?cache=0&sync_timestamp=1593522806175&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-duplicate-keys%2Fdownload%2F%40babel%2Fplugin-transform-duplicate-keys-7.10.4.tgz", - "integrity": "sha1-aX5Qyf7hQ4D+hD0fMGspVhdDHkc=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-exponentiation-operator/download/@babel/plugin-transform-exponentiation-operator-7.10.4.tgz?cache=0&sync_timestamp=1593521230232&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-exponentiation-operator%2Fdownload%2F%40babel%2Fplugin-transform-exponentiation-operator-7.10.4.tgz", - "integrity": "sha1-WuM4xX+M9AAb2zVgeuZrktZlry4=", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-for-of/download/@babel/plugin-transform-for-of-7.10.4.tgz", - "integrity": "sha1-wIiS6IGdOl2ykDGxFa9RHbv+uuk=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-function-name/download/@babel/plugin-transform-function-name-7.10.4.tgz", - "integrity": "sha1-akZ4gOD8ljhRS6NpERgR3b4mRLc=", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/plugin-transform-literals": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-literals/download/@babel/plugin-transform-literals-7.10.4.tgz", - "integrity": "sha1-n0K6CEEQChNfInEtDjkcRi9XHzw=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-member-expression-literals/download/@babel/plugin-transform-member-expression-literals-7.10.4.tgz", - "integrity": "sha1-sexE/PGVr8uNssYs2OVRyIG6+Lc=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-modules-amd/download/@babel/plugin-transform-modules-amd-7.10.5.tgz?cache=0&sync_timestamp=1594750712546&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-modules-amd%2Fdownload%2F%40babel%2Fplugin-transform-modules-amd-7.10.5.tgz", - "integrity": "sha1-G5zdrwXZ6Is6rTOcs+RFxPAgqbE=", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.10.5.tgz", - "integrity": "sha1-Fy9W56Y+eBEvOgQFXyQ2WvcC5+4=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.10.4.tgz?cache=0&sync_timestamp=1593522826853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.10.4.tgz", - "integrity": "sha1-TFxUvgS9MWcKc4J5fXW5+i5bViA=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-transforms%2Fdownload%2F%40babel%2Fhelper-module-transforms-7.10.5.tgz", - "integrity": "sha1-EgwnHAszU2c/zf2MBT2zxUSiYNY=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.10.4.tgz?cache=0&sync_timestamp=1593522827576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha1-UNyWQT1ZT5lad5BZBbBYk813lnM=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.10.4.tgz", - "integrity": "sha1-1YXNk4jqBuYDHkzUS2cTy+rZ5s8=", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-simple-access": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-simple-access/download/@babel/helper-simple-access-7.10.4.tgz?cache=0&sync_timestamp=1593521217867&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-simple-access%2Fdownload%2F%40babel%2Fhelper-simple-access-7.10.4.tgz", - "integrity": "sha1-D1zNopRSd6KnotOoIeFTle3PNGE=", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-modules-commonjs/download/@babel/plugin-transform-modules-commonjs-7.10.4.tgz", - "integrity": "sha1-ZmZ8Pu2h6/eJbUHx8WsXEFovvKA=", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.10.5.tgz", - "integrity": "sha1-Fy9W56Y+eBEvOgQFXyQ2WvcC5+4=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.10.4.tgz?cache=0&sync_timestamp=1593522826853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.10.4.tgz", - "integrity": "sha1-TFxUvgS9MWcKc4J5fXW5+i5bViA=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-transforms%2Fdownload%2F%40babel%2Fhelper-module-transforms-7.10.5.tgz", - "integrity": "sha1-EgwnHAszU2c/zf2MBT2zxUSiYNY=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.10.4.tgz?cache=0&sync_timestamp=1593522827576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha1-UNyWQT1ZT5lad5BZBbBYk813lnM=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.10.4.tgz", - "integrity": "sha1-1YXNk4jqBuYDHkzUS2cTy+rZ5s8=", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-simple-access": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-simple-access/download/@babel/helper-simple-access-7.10.4.tgz?cache=0&sync_timestamp=1593521217867&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-simple-access%2Fdownload%2F%40babel%2Fhelper-simple-access-7.10.4.tgz", - "integrity": "sha1-D1zNopRSd6KnotOoIeFTle3PNGE=", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-modules-systemjs/download/@babel/plugin-transform-modules-systemjs-7.10.5.tgz?cache=0&sync_timestamp=1594750707592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-modules-systemjs%2Fdownload%2F%40babel%2Fplugin-transform-modules-systemjs-7.10.5.tgz", - "integrity": "sha1-YnAJnIVAZmgbrp4F+H4bnK2+jIU=", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.10.5.tgz", - "integrity": "sha1-Fy9W56Y+eBEvOgQFXyQ2WvcC5+4=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.10.4.tgz?cache=0&sync_timestamp=1593522826853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.10.4.tgz", - "integrity": "sha1-TFxUvgS9MWcKc4J5fXW5+i5bViA=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-transforms%2Fdownload%2F%40babel%2Fhelper-module-transforms-7.10.5.tgz", - "integrity": "sha1-EgwnHAszU2c/zf2MBT2zxUSiYNY=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.10.4.tgz?cache=0&sync_timestamp=1593522827576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha1-UNyWQT1ZT5lad5BZBbBYk813lnM=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.10.4.tgz", - "integrity": "sha1-1YXNk4jqBuYDHkzUS2cTy+rZ5s8=", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-simple-access": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-simple-access/download/@babel/helper-simple-access-7.10.4.tgz?cache=0&sync_timestamp=1593521217867&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-simple-access%2Fdownload%2F%40babel%2Fhelper-simple-access-7.10.4.tgz", - "integrity": "sha1-D1zNopRSd6KnotOoIeFTle3PNGE=", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-modules-umd/download/@babel/plugin-transform-modules-umd-7.10.4.tgz?cache=0&sync_timestamp=1593522937615&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-modules-umd%2Fdownload%2F%40babel%2Fplugin-transform-modules-umd-7.10.4.tgz", - "integrity": "sha1-moSB/oG4JGVLOgtl2j34nz0hg54=", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.10.5.tgz", - "integrity": "sha1-Fy9W56Y+eBEvOgQFXyQ2WvcC5+4=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.10.4.tgz?cache=0&sync_timestamp=1593522826853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.10.4.tgz", - "integrity": "sha1-TFxUvgS9MWcKc4J5fXW5+i5bViA=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-transforms%2Fdownload%2F%40babel%2Fhelper-module-transforms-7.10.5.tgz", - "integrity": "sha1-EgwnHAszU2c/zf2MBT2zxUSiYNY=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.10.4.tgz?cache=0&sync_timestamp=1593522827576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha1-UNyWQT1ZT5lad5BZBbBYk813lnM=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.10.4.tgz", - "integrity": "sha1-1YXNk4jqBuYDHkzUS2cTy+rZ5s8=", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-simple-access": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-simple-access/download/@babel/helper-simple-access-7.10.4.tgz?cache=0&sync_timestamp=1593521217867&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-simple-access%2Fdownload%2F%40babel%2Fhelper-simple-access-7.10.4.tgz", - "integrity": "sha1-D1zNopRSd6KnotOoIeFTle3PNGE=", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-named-capturing-groups-regex/download/@babel/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", - "integrity": "sha1-eLTZeIELbzvPA/njGPL8DtQa7LY=", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-new-target/download/@babel/plugin-transform-new-target-7.10.4.tgz?cache=0&sync_timestamp=1593522495673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-new-target%2Fdownload%2F%40babel%2Fplugin-transform-new-target-7.10.4.tgz", - "integrity": "sha1-kJfXU8t7Aky3OBo7LlLpUTqcaIg=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-object-super/download/@babel/plugin-transform-object-super-7.10.4.tgz?cache=0&sync_timestamp=1593522848107&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-object-super%2Fdownload%2F%40babel%2Fplugin-transform-object-super-7.10.4.tgz", - "integrity": "sha1-1xRsTROUM+emUm+IjGZ+MUoJOJQ=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.10.4.tgz?cache=0&sync_timestamp=1593522826253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.10.4.tgz", - "integrity": "sha1-Fo2ho26Q2miujUnA8bSMfGJJITo=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.10.5.tgz", - "integrity": "sha1-G5A1VLyMWD7o0l8eiWlzLmuCmmk=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.10.4.tgz?cache=0&sync_timestamp=1593521218775&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.10.4.tgz", - "integrity": "sha1-0tOyDFmtjEcRL6fSqUvAnV74Lxo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/helper-member-expression-to-functions/download/@babel/helper-member-expression-to-functions-7.10.5.tgz", - "integrity": "sha1-Fy9W56Y+eBEvOgQFXyQ2WvcC5+4=", - "dev": true, - "requires": { - "@babel/types": "^7.10.5" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-optimise-call-expression/download/@babel/helper-optimise-call-expression-7.10.4.tgz?cache=0&sync_timestamp=1593522827576&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-optimise-call-expression%2Fdownload%2F%40babel%2Fhelper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha1-UNyWQT1ZT5lad5BZBbBYk813lnM=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-replace-supers/download/@babel/helper-replace-supers-7.10.4.tgz", - "integrity": "sha1-1YXNk4jqBuYDHkzUS2cTy+rZ5s8=", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.10.4.tgz?cache=0&sync_timestamp=1593522826673&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.10.4.tgz", - "integrity": "sha1-LHBXbqo7VgmyTLmdsoiMw/xCUdE=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.10.5.tgz?cache=0&sync_timestamp=1594750823758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.10.5.tgz", - "integrity": "sha1-58a/Wn3v+VfOyfBLVR4nYpCdgms=", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.4.tgz", - "integrity": "sha1-MlGZbEIA68cdGo/EBfupQPNrong=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.5.tgz", - "integrity": "sha1-d85GT1sli+Jlr2GNj93wU28gtWQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-parameters/download/@babel/plugin-transform-parameters-7.10.5.tgz?cache=0&sync_timestamp=1594750687789&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-parameters%2Fdownload%2F%40babel%2Fplugin-transform-parameters-7.10.5.tgz", - "integrity": "sha1-WdM51Y0LGVBDX0BD504lEABeLEo=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.10.4.tgz?cache=0&sync_timestamp=1593522827189&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.10.4.tgz", - "integrity": "sha1-mMHL6g4jMvM/mkZhuM4VBbLBm6I=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-property-literals/download/@babel/plugin-transform-property-literals-7.10.4.tgz", - "integrity": "sha1-9v5UtlkDUimHhbg+3YFdIUxC48A=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-regenerator/download/@babel/plugin-transform-regenerator-7.10.4.tgz?cache=0&sync_timestamp=1593521089707&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-regenerator%2Fdownload%2F%40babel%2Fplugin-transform-regenerator-7.10.4.tgz", - "integrity": "sha1-IBXlnYOQdOdoON4hWdtCGWb9i2M=", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-reserved-words/download/@babel/plugin-transform-reserved-words-7.10.4.tgz?cache=0&sync_timestamp=1593522496981&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-reserved-words%2Fdownload%2F%40babel%2Fplugin-transform-reserved-words-7.10.4.tgz", - "integrity": "sha1-jyaCvNzvntMn4bCGFYXXAT+KVN0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-runtime/download/@babel/plugin-transform-runtime-7.10.5.tgz?cache=0&sync_timestamp=1594749040036&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-runtime%2Fdownload%2F%40babel%2Fplugin-transform-runtime-7.10.5.tgz", - "integrity": "sha1-Ozm3skgw4MLY/3pEif5c+Z+6zoY=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "resolve": "^1.8.1", - "semver": "^5.5.1" - }, - "dependencies": { - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.10.4.tgz?cache=0&sync_timestamp=1593522826853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.10.4.tgz", - "integrity": "sha1-TFxUvgS9MWcKc4J5fXW5+i5bViA=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-shorthand-properties/download/@babel/plugin-transform-shorthand-properties-7.10.4.tgz", - "integrity": "sha1-n9Jexc3VVbt/Rz5ebuHJce7eTdY=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-spread": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-spread/download/@babel/plugin-transform-spread-7.10.4.tgz?cache=0&sync_timestamp=1593522927458&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-spread%2Fdownload%2F%40babel%2Fplugin-transform-spread-7.10.4.tgz", - "integrity": "sha1-TiyF6g1quu4bJNz7uuQm/o1nTP8=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-sticky-regex/download/@babel/plugin-transform-sticky-regex-7.10.4.tgz", - "integrity": "sha1-jziJ7oZXWBEwop2cyR18c7fEoo0=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-regex": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-template-literals/download/@babel/plugin-transform-template-literals-7.10.5.tgz?cache=0&sync_timestamp=1594750692589&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-template-literals%2Fdownload%2F%40babel%2Fplugin-transform-template-literals-7.10.5.tgz", - "integrity": "sha1-eLxdYmpmQtszEtnQ8AH152Of3ow=", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-typeof-symbol/download/@babel/plugin-transform-typeof-symbol-7.10.4.tgz?cache=0&sync_timestamp=1593522931651&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-typeof-symbol%2Fdownload%2F%40babel%2Fplugin-transform-typeof-symbol-7.10.4.tgz", - "integrity": "sha1-lQnxp+7DHE7b/+E3wWzDP/C8W/w=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-unicode-escapes/download/@babel/plugin-transform-unicode-escapes-7.10.4.tgz", - "integrity": "sha1-/q5SM5HHZR3awRXa4KnQaFeJIAc=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/plugin-transform-unicode-regex/download/@babel/plugin-transform-unicode-regex-7.10.4.tgz?cache=0&sync_timestamp=1593522855498&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-unicode-regex%2Fdownload%2F%40babel%2Fplugin-transform-unicode-regex-7.10.4.tgz", - "integrity": "sha1-5W1x+SgvrG2wnIJ0IFVXbV5tgKg=", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - } - } - }, - "@babel/preset-env": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/preset-env/download/@babel/preset-env-7.10.4.tgz", - "integrity": "sha1-+/V/moA6/Zf08y5PeYu2Lksr718=", - "dev": true, - "requires": { - "@babel/compat-data": "^7.10.4", - "@babel/helper-compilation-targets": "^7.10.4", - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-proposal-async-generator-functions": "^7.10.4", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-proposal-dynamic-import": "^7.10.4", - "@babel/plugin-proposal-json-strings": "^7.10.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", - "@babel/plugin-proposal-numeric-separator": "^7.10.4", - "@babel/plugin-proposal-object-rest-spread": "^7.10.4", - "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", - "@babel/plugin-proposal-optional-chaining": "^7.10.4", - "@babel/plugin-proposal-private-methods": "^7.10.4", - "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-class-properties": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", - "@babel/plugin-syntax-json-strings": "^7.8.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.10.4", - "@babel/plugin-transform-arrow-functions": "^7.10.4", - "@babel/plugin-transform-async-to-generator": "^7.10.4", - "@babel/plugin-transform-block-scoped-functions": "^7.10.4", - "@babel/plugin-transform-block-scoping": "^7.10.4", - "@babel/plugin-transform-classes": "^7.10.4", - "@babel/plugin-transform-computed-properties": "^7.10.4", - "@babel/plugin-transform-destructuring": "^7.10.4", - "@babel/plugin-transform-dotall-regex": "^7.10.4", - "@babel/plugin-transform-duplicate-keys": "^7.10.4", - "@babel/plugin-transform-exponentiation-operator": "^7.10.4", - "@babel/plugin-transform-for-of": "^7.10.4", - "@babel/plugin-transform-function-name": "^7.10.4", - "@babel/plugin-transform-literals": "^7.10.4", - "@babel/plugin-transform-member-expression-literals": "^7.10.4", - "@babel/plugin-transform-modules-amd": "^7.10.4", - "@babel/plugin-transform-modules-commonjs": "^7.10.4", - "@babel/plugin-transform-modules-systemjs": "^7.10.4", - "@babel/plugin-transform-modules-umd": "^7.10.4", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", - "@babel/plugin-transform-new-target": "^7.10.4", - "@babel/plugin-transform-object-super": "^7.10.4", - "@babel/plugin-transform-parameters": "^7.10.4", - "@babel/plugin-transform-property-literals": "^7.10.4", - "@babel/plugin-transform-regenerator": "^7.10.4", - "@babel/plugin-transform-reserved-words": "^7.10.4", - "@babel/plugin-transform-shorthand-properties": "^7.10.4", - "@babel/plugin-transform-spread": "^7.10.4", - "@babel/plugin-transform-sticky-regex": "^7.10.4", - "@babel/plugin-transform-template-literals": "^7.10.4", - "@babel/plugin-transform-typeof-symbol": "^7.10.4", - "@babel/plugin-transform-unicode-escapes": "^7.10.4", - "@babel/plugin-transform-unicode-regex": "^7.10.4", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.10.4", - "browserslist": "^4.12.0", - "core-js-compat": "^3.6.2", - "invariant": "^2.2.2", - "levenary": "^1.1.1", - "semver": "^5.5.0" - }, - "dependencies": { - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.10.4.tgz?cache=0&sync_timestamp=1593522826853&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.10.4.tgz", - "integrity": "sha1-TFxUvgS9MWcKc4J5fXW5+i5bViA=", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.10.4.tgz?cache=0&sync_timestamp=1593521123680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-plugin-utils%2Fdownload%2F%40babel%2Fhelper-plugin-utils-7.10.4.tgz", - "integrity": "sha1-L3WoMSadT2d95JmG3/WZJ1M883U=", - "dev": true - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.5.tgz", - "integrity": "sha1-2Irn4v3oa/v+hR1Nga+nCpl7XRU=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.19.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.19.tgz", - "integrity": "sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=", - "dev": true - } - } - }, - "@babel/preset-modules": { - "version": "0.1.3", - "resolved": "https://registry.npm.taobao.org/@babel/preset-modules/download/@babel/preset-modules-0.1.3.tgz", - "integrity": "sha1-EyQrU7XvjIg8PPfd3VWzbOgPvHI=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/register": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/register/download/@babel/register-7.10.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fregister%2Fdownload%2F%40babel%2Fregister-7.10.1.tgz", - "integrity": "sha1-tlZ8XLUEn0S7+MNdb/aMo8QyOO0=", - "dev": true, - "requires": { - "find-cache-dir": "^2.0.0", - "lodash": "^4.17.13", - "make-dir": "^2.1.0", - "pirates": "^4.0.0", - "source-map-support": "^0.5.16" - } - }, - "@babel/runtime": { - "version": "7.10.5", - "resolved": "https://registry.npm.taobao.org/@babel/runtime/download/@babel/runtime-7.10.5.tgz?cache=0&sync_timestamp=1594749041890&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.10.5.tgz", - "integrity": "sha1-MD2L1EDs1aSR6uYRf9M2dphnTFw=", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.5", - "resolved": "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.13.5.tgz?cache=0&sync_timestamp=1584052597708&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.5.tgz", - "integrity": "sha1-2Hih0JS0MG0QuQlkhLM+vVXiZpc=", - "dev": true - } - } - }, - "@babel/template": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.10.1.tgz", - "integrity": "sha1-4WcVSpTLXxSyjcWPU1bSFi9TmBE=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/parser": "^7.10.1", - "@babel/types": "^7.10.1" - } - }, - "@babel/traverse": { - "version": "7.10.1", - "resolved": "https://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.10.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.10.1.tgz", - "integrity": "sha1-u87zAx5BUqbAtQFH9JWN9Uyg3Sc=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.1", - "@babel/generator": "^7.10.1", - "@babel/helper-function-name": "^7.10.1", - "@babel/helper-split-export-declaration": "^7.10.1", - "@babel/parser": "^7.10.1", - "@babel/types": "^7.10.1", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "@babel/types": { - "version": "7.10.2", - "resolved": "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.10.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.10.2.tgz", - "integrity": "sha1-MCg74xytDb9vsAvUBkHKDqZ1Fy0=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.1", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/@cnakazawa/watch/download/@cnakazawa/watch-1.0.4.tgz", - "integrity": "sha1-+GSuhQBND8q29QvpFBxNo2jRZWo=", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, - "@fortawesome/fontawesome-common-types": { - "version": "0.2.29", - "resolved": "https://registry.npm.taobao.org/@fortawesome/fontawesome-common-types/download/@fortawesome/fontawesome-common-types-0.2.29.tgz", - "integrity": "sha1-4aRWtkMjdGLTkDBMq2l1/z/Wg5c=" - }, - "@fortawesome/fontawesome-svg-core": { - "version": "1.2.29", - "resolved": "https://registry.npm.taobao.org/@fortawesome/fontawesome-svg-core/download/@fortawesome/fontawesome-svg-core-1.2.29.tgz", - "integrity": "sha1-NO8ygkZkU0+eTvN5guvyhriZoYk=", - "requires": { - "@fortawesome/fontawesome-common-types": "^0.2.29" - } - }, - "@fortawesome/free-brands-svg-icons": { - "version": "5.13.1", - "resolved": "https://registry.npm.taobao.org/@fortawesome/free-brands-svg-icons/download/@fortawesome/free-brands-svg-icons-5.13.1.tgz", - "integrity": "sha1-/vB6S5V9wXCPIZGpTN/NaQHDU4M=", - "requires": { - "@fortawesome/fontawesome-common-types": "^0.2.29" - } - }, - "@fortawesome/free-regular-svg-icons": { - "version": "5.13.1", - "resolved": "https://registry.npm.taobao.org/@fortawesome/free-regular-svg-icons/download/@fortawesome/free-regular-svg-icons-5.13.1.tgz", - "integrity": "sha1-AqwML9UpSNITnso8pCsmfxfj1yU=", - "requires": { - "@fortawesome/fontawesome-common-types": "^0.2.29" - } - }, - "@fortawesome/free-solid-svg-icons": { - "version": "5.13.1", - "resolved": "https://registry.npm.taobao.org/@fortawesome/free-solid-svg-icons/download/@fortawesome/free-solid-svg-icons-5.13.1.tgz", - "integrity": "sha1-AQqEa3GKDxELPNE30HJjm06L1Bo=", - "requires": { - "@fortawesome/fontawesome-common-types": "^0.2.29" - } - }, - "@fortawesome/vue-fontawesome": { - "version": "0.1.10", - "resolved": "https://registry.npm.taobao.org/@fortawesome/vue-fontawesome/download/@fortawesome/vue-fontawesome-0.1.10.tgz", - "integrity": "sha1-7u7B5OiFC+0EaPk4KSsGzaeTvzQ=" - }, - "@hapi/address": { - "version": "2.1.4", - "resolved": "https://registry.npm.taobao.org/@hapi/address/download/@hapi/address-2.1.4.tgz?cache=0&sync_timestamp=1593993895205&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Faddress%2Fdownload%2F%40hapi%2Faddress-2.1.4.tgz", - "integrity": "sha1-XWftQ/P9QaadS5/3tW58DR0KgeU=", - "dev": true - }, - "@hapi/bourne": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/@hapi/bourne/download/@hapi/bourne-1.3.2.tgz?cache=0&sync_timestamp=1593915150444&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Fbourne%2Fdownload%2F%40hapi%2Fbourne-1.3.2.tgz", - "integrity": "sha1-CnCVreoGckPOMoPhtWuKj0U7JCo=", - "dev": true - }, - "@hapi/hoek": { - "version": "8.5.1", - "resolved": "https://registry.npm.taobao.org/@hapi/hoek/download/@hapi/hoek-8.5.1.tgz?cache=0&sync_timestamp=1593915910245&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Fhoek%2Fdownload%2F%40hapi%2Fhoek-8.5.1.tgz", - "integrity": "sha1-/elgZMpEbeyMVajC8TCVewcMbgY=", - "dev": true - }, - "@hapi/joi": { - "version": "15.1.1", - "resolved": "https://registry.npm.taobao.org/@hapi/joi/download/@hapi/joi-15.1.1.tgz", - "integrity": "sha1-xnW4pxKW8Cgz+NbSQ7NMV7jOGdc=", - "dev": true, - "requires": { - "@hapi/address": "2.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/topo": "3.x.x" - } - }, - "@hapi/topo": { - "version": "3.1.6", - "resolved": "https://registry.npm.taobao.org/@hapi/topo/download/@hapi/topo-3.1.6.tgz?cache=0&sync_timestamp=1593916080558&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Ftopo%2Fdownload%2F%40hapi%2Ftopo-3.1.6.tgz", - "integrity": "sha1-aNk1+j6uf91asNf5U/MgXYsr/Ck=", - "dev": true, - "requires": { - "@hapi/hoek": "^8.3.0" - } - }, - "@intervolga/optimize-cssnano-plugin": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/@intervolga/optimize-cssnano-plugin/download/@intervolga/optimize-cssnano-plugin-1.0.6.tgz", - "integrity": "sha1-vnx4RhKLiPapsdEmGgrQbrXA/fg=", - "dev": true, - "requires": { - "cssnano": "^4.0.0", - "cssnano-preset-default": "^4.0.0", - "postcss": "^7.0.0" - } - }, - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/console/download/@jest/console-24.9.0.tgz?cache=0&sync_timestamp=1592926444599&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Fconsole%2Fdownload%2F%40jest%2Fconsole-24.9.0.tgz", - "integrity": "sha1-ebG8Bvt0qM+wHL3t+UVYSxuXB/A=", - "dev": true, - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/core": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/core/download/@jest/core-24.9.0.tgz?cache=0&sync_timestamp=1592926073448&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Fcore%2Fdownload%2F%40jest%2Fcore-24.9.0.tgz", - "integrity": "sha1-LOzNC5MYH5xIUOdPKprUPTUTacQ=", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/reporters": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-changed-files": "^24.9.0", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-resolve-dependencies": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "jest-watcher": "^24.9.0", - "micromatch": "^3.1.10", - "p-each-series": "^1.0.0", - "realpath-native": "^1.1.0", - "rimraf": "^2.5.4", - "slash": "^2.0.0", - "strip-ansi": "^5.0.0" - } - }, - "@jest/environment": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/environment/download/@jest/environment-24.9.0.tgz?cache=0&sync_timestamp=1592926444790&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Fenvironment%2Fdownload%2F%40jest%2Fenvironment-24.9.0.tgz", - "integrity": "sha1-IeOvotZcBYbL1svv4gi6+t5Eqxg=", - "dev": true, - "requires": { - "@jest/fake-timers": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/fake-timers/download/@jest/fake-timers-24.9.0.tgz?cache=0&sync_timestamp=1592926443711&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ffake-timers%2Fdownload%2F%40jest%2Ffake-timers-24.9.0.tgz", - "integrity": "sha1-uj5r8O7NCaY2BJiWQ00wZjZUDJM=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/reporters/download/@jest/reporters-24.9.0.tgz", - "integrity": "sha1-hmYO/44rlmHQQqjpigKLjWMaW0M=", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.2", - "istanbul-lib-instrument": "^3.0.1", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.2.6", - "jest-haste-map": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "node-notifier": "^5.4.2", - "slash": "^2.0.0", - "source-map": "^0.6.0", - "string-length": "^2.0.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/source-map/download/@jest/source-map-24.9.0.tgz?cache=0&sync_timestamp=1592927131369&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Fsource-map%2Fdownload%2F%40jest%2Fsource-map-24.9.0.tgz", - "integrity": "sha1-DiY6lEML5LQdpoPMwea//ioZFxQ=", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/test-result/download/@jest/test-result-24.9.0.tgz?cache=0&sync_timestamp=1592926445863&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ftest-result%2Fdownload%2F%40jest%2Ftest-result-24.9.0.tgz", - "integrity": "sha1-EXluiqnb+I6gJXV7MVJZWtBroMo=", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/test-sequencer": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/test-sequencer/download/@jest/test-sequencer-24.9.0.tgz?cache=0&sync_timestamp=1592926064241&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ftest-sequencer%2Fdownload%2F%40jest%2Ftest-sequencer-24.9.0.tgz", - "integrity": "sha1-+PM081tiWk8vNV8v5+YDba0uazE=", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" - } - }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/transform/download/@jest/transform-24.9.0.tgz?cache=0&sync_timestamp=1592926445716&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ftransform%2Fdownload%2F%40jest%2Ftransform-24.9.0.tgz", - "integrity": "sha1-SuJ2iyllU/rasJ6ewRlUPJCxbFY=", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" - }, - "dependencies": { - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npm.taobao.org/write-file-atomic/download/write-file-atomic-2.4.1.tgz?cache=0&sync_timestamp=1582584103455&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwrite-file-atomic%2Fdownload%2Fwrite-file-atomic-2.4.1.tgz", - "integrity": "sha1-0LBUY8GIroBDlv1asqNwBir4dSk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - } - } - }, - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/types/download/@jest/types-24.9.0.tgz?cache=0&sync_timestamp=1592926441617&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ftypes%2Fdownload%2F%40jest%2Ftypes-24.9.0.tgz", - "integrity": "sha1-Y8smy3UA0Gnlo4lEGnxqtekJ/Fk=", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/@mrmlnc/readdir-enhanced/download/@mrmlnc/readdir-enhanced-2.2.1.tgz", - "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/@nodelib/fs.stat/download/@nodelib/fs.stat-1.1.3.tgz", - "integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=", - "dev": true - }, - "@soda/friendly-errors-webpack-plugin": { - "version": "1.7.1", - "resolved": "https://registry.npm.taobao.org/@soda/friendly-errors-webpack-plugin/download/@soda/friendly-errors-webpack-plugin-1.7.1.tgz", - "integrity": "sha1-cG9kvLSouWQrSK46zkRMcDNNYV0=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "error-stack-parser": "^2.0.0", - "string-width": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-2.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-1.1.3.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-2.0.0.tgz?cache=0&sync_timestamp=1569557271992&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "@soda/get-current-script": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/@soda/get-current-script/download/@soda/get-current-script-1.0.2.tgz", - "integrity": "sha1-pTUV2yXYA4N0OBtzryC7Ty5QjYc=", - "dev": true - }, - "@tinymce/tinymce-vue": { - "version": "3.2.2", - "resolved": "https://registry.npm.taobao.org/@tinymce/tinymce-vue/download/@tinymce/tinymce-vue-3.2.2.tgz", - "integrity": "sha1-oWUA++6/7ErkP06f5b1zmutmo9Y=" - }, - "@types/babel__core": { - "version": "7.1.9", - "resolved": "https://registry.npm.taobao.org/@types/babel__core/download/@types/babel__core-7.1.9.tgz?cache=0&sync_timestamp=1592728527027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fbabel__core%2Fdownload%2F%40types%2Fbabel__core-7.1.9.tgz", - "integrity": "sha1-d+WdQ4UipvuJj6Q9w0VcbnLzlj0=", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.1", - "resolved": "https://registry.npm.taobao.org/@types/babel__generator/download/@types/babel__generator-7.6.1.tgz", - "integrity": "sha1-SQF2ezl+hxGuuZ3405bXunt/DgQ=", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npm.taobao.org/@types/babel__template/download/@types/babel__template-7.0.2.tgz?cache=0&sync_timestamp=1588199666194&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fbabel__template%2Fdownload%2F%40types%2Fbabel__template-7.0.2.tgz", - "integrity": "sha1-T/Y9a1Lt2sHee5daUiPtMuzqkwc=", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.0.13", - "resolved": "https://registry.npm.taobao.org/@types/babel__traverse/download/@types/babel__traverse-7.0.13.tgz?cache=0&sync_timestamp=1594066835128&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fbabel__traverse%2Fdownload%2F%40types%2Fbabel__traverse-7.0.13.tgz", - "integrity": "sha1-GHSRS+l0pJLhtMsAWFyrsnTouhg=", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/@types/color-name/download/@types/color-name-1.1.1.tgz", - "integrity": "sha1-HBJhu+qhCoBVu8XYq4S3sq/IRqA=", - "dev": true - }, - "@types/glob": { - "version": "7.1.2", - "resolved": "https://registry.npm.taobao.org/@types/glob/download/@types/glob-7.1.2.tgz?cache=0&sync_timestamp=1594077991058&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fglob%2Fdownload%2F%40types%2Fglob-7.1.2.tgz", - "integrity": "sha1-BsomUhNTpUXZSgrcdPOKWdIyyYc=", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/@types/istanbul-lib-coverage/download/@types/istanbul-lib-coverage-2.0.3.tgz?cache=0&sync_timestamp=1591718768161&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fistanbul-lib-coverage%2Fdownload%2F%40types%2Fistanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha1-S6jdtyAiH0MuRDvV+RF/0iz9R2I=", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/@types/istanbul-lib-report/download/@types/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha1-wUwk8Y6oGQwRjudWK3/5mjZVJoY=", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@types/istanbul-reports/download/@types/istanbul-reports-1.1.2.tgz", - "integrity": "sha1-6HXMaJ5HvOVJ7IHz315vbxHPrrI=", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "24.9.1", - "resolved": "https://registry.npm.taobao.org/@types/jest/download/@types/jest-24.9.1.tgz?cache=0&sync_timestamp=1595087611332&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjest%2Fdownload%2F%40types%2Fjest-24.9.1.tgz", - "integrity": "sha1-Arr5Vzx48bmXSl82d4s2aqd71TQ=", - "dev": true, - "requires": { - "jest-diff": "^24.3.0" - } - }, - "@types/json-schema": { - "version": "7.0.5", - "resolved": "https://registry.npm.taobao.org/@types/json-schema/download/@types/json-schema-7.0.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.5.tgz", - "integrity": "sha1-3M5EMOZLRDuolF8CkPtWStW6xt0=", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/@types/minimatch/download/@types/minimatch-3.0.3.tgz", - "integrity": "sha1-PcoOPzOyAPx9ETnAzZbBJoyt/Z0=", - "dev": true - }, - "@types/node": { - "version": "14.0.13", - "resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-14.0.13.tgz?cache=0&sync_timestamp=1594656014203&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-14.0.13.tgz", - "integrity": "sha1-7hEo6IG4dMNxN0wfciAYk2FkF8k=", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npm.taobao.org/@types/normalize-package-data/download/@types/normalize-package-data-2.4.0.tgz", - "integrity": "sha1-5IbQ2XOW15vu3QpuM/RTT/a0lz4=", - "dev": true - }, - "@types/q": { - "version": "1.5.4", - "resolved": "https://registry.npm.taobao.org/@types/q/download/@types/q-1.5.4.tgz?cache=0&sync_timestamp=1589585559499&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fq%2Fdownload%2F%40types%2Fq-1.5.4.tgz", - "integrity": "sha1-FZJUFOCtLNdlv+9YhC9+JqesyyQ=", - "dev": true - }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/@types/stack-utils/download/@types/stack-utils-1.0.1.tgz", - "integrity": "sha1-CoUdO9lkmPolwzq3J47TvWXwbD4=", - "dev": true - }, - "@types/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/@types/strip-bom/download/@types/strip-bom-3.0.0.tgz", - "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", - "dev": true - }, - "@types/strip-json-comments": { - "version": "0.0.30", - "resolved": "https://registry.npm.taobao.org/@types/strip-json-comments/download/@types/strip-json-comments-0.0.30.tgz", - "integrity": "sha1-mqMMBNshKpoGSdaub9UKzMQHSKE=", - "dev": true - }, - "@types/yargs": { - "version": "13.0.9", - "resolved": "https://registry.npm.taobao.org/@types/yargs/download/@types/yargs-13.0.9.tgz", - "integrity": "sha1-RAKOl0NDx6/POWDxorEJnDmnteE=", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npm.taobao.org/@types/yargs-parser/download/@types/yargs-parser-15.0.0.tgz", - "integrity": "sha1-yz+fdBhp4gzOMw/765JxWQSDiC0=", - "dev": true - }, - "@vue/babel-helper-vue-jsx-merge-props": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.0.0.tgz", - "integrity": "sha1-BI/leZWNpAj7eosqPsBQtQpmEEA=", - "dev": true - }, - "@vue/babel-plugin-transform-vue-jsx": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-plugin-transform-vue-jsx/download/@vue/babel-plugin-transform-vue-jsx-1.1.2.tgz", - "integrity": "sha1-wKPm78Ai515CR7RIqPxrhvA+kcA=", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", - "html-tags": "^2.0.0", - "lodash.kebabcase": "^4.1.1", - "svg-tags": "^1.0.0" - } - }, - "@vue/babel-preset-app": { - "version": "4.4.4", - "resolved": "https://registry.npm.taobao.org/@vue/babel-preset-app/download/@vue/babel-preset-app-4.4.4.tgz?cache=0&sync_timestamp=1592976616638&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-preset-app%2Fdownload%2F%40vue%2Fbabel-preset-app-4.4.4.tgz", - "integrity": "sha1-5AkpyonqPVR+ogzwoVwiLJrRujg=", - "dev": true, - "requires": { - "@babel/core": "^7.9.6", - "@babel/helper-compilation-targets": "^7.9.6", - "@babel/helper-module-imports": "^7.8.3", - "@babel/plugin-proposal-class-properties": "^7.8.3", - "@babel/plugin-proposal-decorators": "^7.8.3", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-jsx": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.9.6", - "@babel/preset-env": "^7.9.6", - "@babel/runtime": "^7.9.6", - "@vue/babel-preset-jsx": "^1.1.2", - "babel-plugin-dynamic-import-node": "^2.3.3", - "core-js": "^3.6.5", - "core-js-compat": "^3.6.5", - "semver": "^6.1.0" - }, - "dependencies": { - "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npm.taobao.org/core-js/download/core-js-3.6.5.tgz", - "integrity": "sha1-c5XcJzrzf7LlDpvT2f6EEoUjHRo=", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "@vue/babel-preset-jsx": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-preset-jsx/download/@vue/babel-preset-jsx-1.1.2.tgz?cache=0&sync_timestamp=1573270721644&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-preset-jsx%2Fdownload%2F%40vue%2Fbabel-preset-jsx-1.1.2.tgz", - "integrity": "sha1-LhaetMIE6jfKZsLqhaiAv8mdTyA=", - "dev": true, - "requires": { - "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", - "@vue/babel-sugar-functional-vue": "^1.1.2", - "@vue/babel-sugar-inject-h": "^1.1.2", - "@vue/babel-sugar-v-model": "^1.1.2", - "@vue/babel-sugar-v-on": "^1.1.2" - } - }, - "@vue/babel-sugar-functional-vue": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-functional-vue/download/@vue/babel-sugar-functional-vue-1.1.2.tgz", - "integrity": "sha1-9+JPugnm8e5wEEVgqICAV1VfGpo=", - "dev": true, - "requires": { - "@babel/plugin-syntax-jsx": "^7.2.0" - } - }, - "@vue/babel-sugar-inject-h": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-inject-h/download/@vue/babel-sugar-inject-h-1.1.2.tgz", - "integrity": "sha1-ilJ2ttji7Rb/yAeKrZQjYnTm7fA=", - "dev": true, - "requires": { - "@babel/plugin-syntax-jsx": "^7.2.0" - } - }, - "@vue/babel-sugar-v-model": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-v-model/download/@vue/babel-sugar-v-model-1.1.2.tgz", - "integrity": "sha1-H/b9G4ACI/ycsehNzrXlLXN6gZI=", - "dev": true, - "requires": { - "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", - "camelcase": "^5.0.0", - "html-tags": "^2.0.0", - "svg-tags": "^1.0.0" - } - }, - "@vue/babel-sugar-v-on": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/babel-sugar-v-on/download/@vue/babel-sugar-v-on-1.1.2.tgz?cache=0&sync_timestamp=1573270721318&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-sugar-v-on%2Fdownload%2F%40vue%2Fbabel-sugar-v-on-1.1.2.tgz", - "integrity": "sha1-su+ZuPL6sJ++rSWq1w70Lhz1sTs=", - "dev": true, - "requires": { - "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", - "camelcase": "^5.0.0" - } - }, - "@vue/cli-overlay": { - "version": "4.4.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-overlay/download/@vue/cli-overlay-4.4.4.tgz?cache=0&sync_timestamp=1592976616871&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-overlay%2Fdownload%2F%40vue%2Fcli-overlay-4.4.4.tgz", - "integrity": "sha1-QyaKjNzTrXQd+lEAa1dgZPu+bo4=", - "dev": true - }, - "@vue/cli-plugin-babel": { - "version": "4.4.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-babel/download/@vue/cli-plugin-babel-4.4.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-plugin-babel%2Fdownload%2F%40vue%2Fcli-plugin-babel-4.4.4.tgz", - "integrity": "sha1-GJBLXjgXMpGzcFTC8Dk/uMdI83s=", - "dev": true, - "requires": { - "@babel/core": "^7.9.6", - "@vue/babel-preset-app": "^4.4.4", - "@vue/cli-shared-utils": "^4.4.4", - "babel-loader": "^8.1.0", - "cache-loader": "^4.1.0", - "thread-loader": "^2.1.3", - "webpack": "^4.0.0" - } - }, - "@vue/cli-plugin-eslint": { - "version": "4.4.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-eslint/download/@vue/cli-plugin-eslint-4.4.4.tgz?cache=0&sync_timestamp=1592976616855&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-plugin-eslint%2Fdownload%2F%40vue%2Fcli-plugin-eslint-4.4.4.tgz", - "integrity": "sha1-Gf0doYY6kFhLeJOczhzpTEntQ4g=", - "dev": true, - "requires": { - "@vue/cli-shared-utils": "^4.4.4", - "eslint-loader": "^2.2.1", - "globby": "^9.2.0", - "inquirer": "^7.1.0", - "webpack": "^4.0.0", - "yorkie": "^2.0.0" - } - }, - "@vue/cli-plugin-router": { - "version": "4.4.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-router/download/@vue/cli-plugin-router-4.4.4.tgz?cache=0&sync_timestamp=1592976471403&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-plugin-router%2Fdownload%2F%40vue%2Fcli-plugin-router-4.4.4.tgz", - "integrity": "sha1-WeEd1V34VGGGFq1PATsgxS5KOmg=", - "dev": true, - "requires": { - "@vue/cli-shared-utils": "^4.4.4" - } - }, - "@vue/cli-plugin-unit-jest": { - "version": "4.4.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-unit-jest/download/@vue/cli-plugin-unit-jest-4.4.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-plugin-unit-jest%2Fdownload%2F%40vue%2Fcli-plugin-unit-jest-4.4.4.tgz", - "integrity": "sha1-oi4p7FruNPI+RNLA8+fXo72MGcw=", - "dev": true, - "requires": { - "@babel/core": "^7.9.6", - "@babel/plugin-transform-modules-commonjs": "^7.9.6", - "@types/jest": "^24.0.19", - "@vue/cli-shared-utils": "^4.4.4", - "babel-core": "^7.0.0-bridge.0", - "babel-jest": "^24.9.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", - "deepmerge": "^4.2.2", - "jest": "^24.9.0", - "jest-environment-jsdom-fifteen": "^1.0.2", - "jest-serializer-vue": "^2.0.2", - "jest-transform-stub": "^2.0.0", - "jest-watch-typeahead": "^0.4.2", - "ts-jest": "^24.2.0", - "vue-jest": "^3.0.5" - }, - "dependencies": { - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/babel-jest/download/babel-jest-24.9.0.tgz?cache=0&sync_timestamp=1592926057142&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-jest%2Fdownload%2Fbabel-jest-24.9.0.tgz", - "integrity": "sha1-P8Mny4RnuJ0U17xw4xUQSng8zVQ=", - "dev": true, - "requires": { - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.9.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" - }, - "dependencies": { - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/@jest/transform/download/@jest/transform-24.9.0.tgz?cache=0&sync_timestamp=1592926445716&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ftransform%2Fdownload%2F%40jest%2Ftransform-24.9.0.tgz", - "integrity": "sha1-SuJ2iyllU/rasJ6ewRlUPJCxbFY=", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" - } - }, - "@types/babel__core": { - "version": "7.1.9", - "resolved": "https://registry.npm.taobao.org/@types/babel__core/download/@types/babel__core-7.1.9.tgz?cache=0&sync_timestamp=1592728527027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fbabel__core%2Fdownload%2F%40types%2Fbabel__core-7.1.9.tgz", - "integrity": "sha1-d+WdQ4UipvuJj6Q9w0VcbnLzlj0=", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__traverse": { - "version": "7.0.13", - "resolved": "https://registry.npm.taobao.org/@types/babel__traverse/download/@types/babel__traverse-7.0.13.tgz?cache=0&sync_timestamp=1594066835128&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fbabel__traverse%2Fdownload%2F%40types%2Fbabel__traverse-7.0.13.tgz", - "integrity": "sha1-GHSRS+l0pJLhtMsAWFyrsnTouhg=", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-istanbul/download/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha1-30reg9iXqS3wacTZolzyZxKTyFQ=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" - } - } - } - }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-jest-hoist/download/babel-plugin-jest-hoist-24.9.0.tgz?cache=0&sync_timestamp=1592926445554&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-plugin-jest-hoist%2Fdownload%2Fbabel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha1-T4NwketAfgFEfIhDy+xUbQAC11Y=", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" - }, - "dependencies": { - "@types/babel__traverse": { - "version": "7.0.13", - "resolved": "https://registry.npm.taobao.org/@types/babel__traverse/download/@types/babel__traverse-7.0.13.tgz?cache=0&sync_timestamp=1594066835128&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fbabel__traverse%2Fdownload%2F%40types%2Fbabel__traverse-7.0.13.tgz", - "integrity": "sha1-GHSRS+l0pJLhtMsAWFyrsnTouhg=", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - } - } - }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/babel-preset-jest/download/babel-preset-jest-24.9.0.tgz?cache=0&sync_timestamp=1592927135667&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-preset-jest%2Fdownload%2Fbabel-preset-jest-24.9.0.tgz", - "integrity": "sha1-GStSHiIX+x0fZ89z9wwzZlCtPNw=", - "dev": true, - "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" - } - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npm.taobao.org/deepmerge/download/deepmerge-4.2.2.tgz?cache=0&sync_timestamp=1572279720382&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdeepmerge%2Fdownload%2Fdeepmerge-4.2.2.tgz", - "integrity": "sha1-RNLqNnm49NT/ujPwPYZfwee/SVU=", - "dev": true - }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npm.taobao.org/write-file-atomic/download/write-file-atomic-2.4.1.tgz?cache=0&sync_timestamp=1582584103455&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwrite-file-atomic%2Fdownload%2Fwrite-file-atomic-2.4.1.tgz", - "integrity": "sha1-0LBUY8GIroBDlv1asqNwBir4dSk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - } - } - }, - "@vue/cli-plugin-vuex": { - "version": "4.4.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-vuex/download/@vue/cli-plugin-vuex-4.4.4.tgz?cache=0&sync_timestamp=1592976615977&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-plugin-vuex%2Fdownload%2F%40vue%2Fcli-plugin-vuex-4.4.4.tgz", - "integrity": "sha1-QjKMFhl4gjoerJegeDKnqiJcu5s=", - "dev": true - }, - "@vue/cli-service": { - "version": "4.4.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-service/download/@vue/cli-service-4.4.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-service%2Fdownload%2F%40vue%2Fcli-service-4.4.4.tgz", - "integrity": "sha1-JWyZDkmi/43FM7dzxQSmVDXHXEw=", - "dev": true, - "requires": { - "@intervolga/optimize-cssnano-plugin": "^1.0.5", - "@soda/friendly-errors-webpack-plugin": "^1.7.1", - "@soda/get-current-script": "^1.0.0", - "@vue/cli-overlay": "^4.4.4", - "@vue/cli-plugin-router": "^4.4.4", - "@vue/cli-plugin-vuex": "^4.4.4", - "@vue/cli-shared-utils": "^4.4.4", - "@vue/component-compiler-utils": "^3.1.2", - "@vue/preload-webpack-plugin": "^1.1.0", - "@vue/web-component-wrapper": "^1.2.0", - "acorn": "^7.2.0", - "acorn-walk": "^7.1.1", - "address": "^1.1.2", - "autoprefixer": "^9.8.0", - "browserslist": "^4.12.0", - "cache-loader": "^4.1.0", - "case-sensitive-paths-webpack-plugin": "^2.3.0", - "cli-highlight": "^2.1.4", - "clipboardy": "^2.3.0", - "cliui": "^6.0.0", - "copy-webpack-plugin": "^5.1.1", - "css-loader": "^3.5.3", - "cssnano": "^4.1.10", - "debug": "^4.1.1", - "default-gateway": "^5.0.5", - "dotenv": "^8.2.0", - "dotenv-expand": "^5.1.0", - "file-loader": "^4.2.0", - "fs-extra": "^7.0.1", - "globby": "^9.2.0", - "hash-sum": "^2.0.0", - "html-webpack-plugin": "^3.2.0", - "launch-editor-middleware": "^2.2.1", - "lodash.defaultsdeep": "^4.6.1", - "lodash.mapvalues": "^4.6.0", - "lodash.transform": "^4.6.0", - "mini-css-extract-plugin": "^0.9.0", - "minimist": "^1.2.5", - "pnp-webpack-plugin": "^1.6.4", - "portfinder": "^1.0.26", - "postcss-loader": "^3.0.0", - "ssri": "^7.1.0", - "terser-webpack-plugin": "^2.3.6", - "thread-loader": "^2.1.3", - "url-loader": "^2.2.0", - "vue-loader": "^15.9.2", - "vue-style-loader": "^4.1.2", - "webpack": "^4.0.0", - "webpack-bundle-analyzer": "^3.8.0", - "webpack-chain": "^6.4.0", - "webpack-dev-server": "^3.11.0", - "webpack-merge": "^4.2.2" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-5.0.0.tgz", - "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.2.1.tgz", - "integrity": "sha1-kK51xCTQCNJiTFvynq0xd+v881k=", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-6.0.0.tgz?cache=0&sync_timestamp=1573943458671&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-6.0.0.tgz", - "integrity": "sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE=", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-8.0.0.tgz", - "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", - "dev": true - }, - "ssri": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/ssri/download/ssri-7.1.0.tgz", - "integrity": "sha1-ksJBv23oI2W1x/tL126XVSLhKU0=", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1", - "minipass": "^3.1.1" - }, - "dependencies": { - "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npm.taobao.org/minipass/download/minipass-3.1.3.tgz?cache=0&sync_timestamp=1589332828776&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminipass%2Fdownload%2Fminipass-3.1.3.tgz", - "integrity": "sha1-fUL/HzljVILhX5zbUxhN7r1YFf0=", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-4.2.0.tgz", - "integrity": "sha1-lSGCxGzHssMT0VluYjmSvRY7crU=", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-6.0.0.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-6.0.0.tgz", - "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz", - "integrity": "sha1-6Tk7oHEC5skaOyIUePAlfNKFblM=", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", - "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", - "dev": true - } - } - }, - "@vue/cli-shared-utils": { - "version": "4.4.4", - "resolved": "https://registry.npm.taobao.org/@vue/cli-shared-utils/download/@vue/cli-shared-utils-4.4.4.tgz", - "integrity": "sha1-uWhbc6YEyKfugtb8Mxn+e7LNsnQ=", - "dev": true, - "requires": { - "@hapi/joi": "^15.0.1", - "chalk": "^2.4.2", - "execa": "^1.0.0", - "launch-editor": "^2.2.1", - "lru-cache": "^5.1.1", - "node-ipc": "^9.1.1", - "open": "^6.3.0", - "ora": "^3.4.0", - "read-pkg": "^5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "semver": "^6.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-5.0.0.tgz", - "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-6.0.0.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-6.0.0.tgz", - "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "@vue/component-compiler-utils": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/@vue/component-compiler-utils/download/@vue/component-compiler-utils-3.1.2.tgz?cache=0&sync_timestamp=1586331302562&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcomponent-compiler-utils%2Fdownload%2F%40vue%2Fcomponent-compiler-utils-3.1.2.tgz", - "integrity": "sha1-ghOl/zIC+fITf+VTcPnouWVggcM=", - "dev": true, - "requires": { - "consolidate": "^0.15.1", - "hash-sum": "^1.0.2", - "lru-cache": "^4.1.2", - "merge-source-map": "^1.1.0", - "postcss": "^7.0.14", - "postcss-selector-parser": "^6.0.2", - "prettier": "^1.18.2", - "source-map": "~0.6.1", - "vue-template-es2015-compiler": "^1.9.0" - }, - "dependencies": { - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, - "@vue/preload-webpack-plugin": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/@vue/preload-webpack-plugin/download/@vue/preload-webpack-plugin-1.1.1.tgz", - "integrity": "sha1-GHI1MNME9EMCHaIpLW7JUCgmEEo=", - "dev": true - }, - "@vue/test-utils": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/@vue/test-utils/download/@vue/test-utils-1.0.3.tgz", - "integrity": "sha1-WHxN2bQktmAi8YjBm8YF2izpHG8=", - "dev": true, - "requires": { - "dom-event-types": "^1.0.0", - "lodash": "^4.17.15", - "pretty": "^2.0.0" - } - }, - "@vue/web-component-wrapper": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/@vue/web-component-wrapper/download/@vue/web-component-wrapper-1.2.0.tgz", - "integrity": "sha1-uw5G8VhafiibTuYGfcxaauYvHdE=", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/ast/download/@webassemblyjs/ast-1.9.0.tgz?cache=0&sync_timestamp=1580599461432&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fast%2Fdownload%2F%40webassemblyjs%2Fast-1.9.0.tgz", - "integrity": "sha1-vYUGBLQEJFmlpBzX0zjL7Wle2WQ=", - "dev": true, - "requires": { - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/floating-point-hex-parser/download/@webassemblyjs/floating-point-hex-parser-1.9.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Ffloating-point-hex-parser%2Fdownload%2F%40webassemblyjs%2Ffloating-point-hex-parser-1.9.0.tgz", - "integrity": "sha1-PD07Jxvd/ITesA9xNEQ4MR1S/7Q=", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-api-error/download/@webassemblyjs/helper-api-error-1.9.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-api-error%2Fdownload%2F%40webassemblyjs%2Fhelper-api-error-1.9.0.tgz", - "integrity": "sha1-ID9nbjM7lsnaLuqzzO8zxFkotqI=", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-buffer/download/@webassemblyjs/helper-buffer-1.9.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-buffer%2Fdownload%2F%40webassemblyjs%2Fhelper-buffer-1.9.0.tgz", - "integrity": "sha1-oUQtJpxf6yP8vJ73WdrDVH8p3gA=", - "dev": true - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-code-frame/download/@webassemblyjs/helper-code-frame-1.9.0.tgz", - "integrity": "sha1-ZH+Iks0gQ6gqwMjF51w28dkVnyc=", - "dev": true, - "requires": { - "@webassemblyjs/wast-printer": "1.9.0" - } - }, - "@webassemblyjs/helper-fsm": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-fsm/download/@webassemblyjs/helper-fsm-1.9.0.tgz?cache=0&sync_timestamp=1580599471846&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-fsm%2Fdownload%2F%40webassemblyjs%2Fhelper-fsm-1.9.0.tgz", - "integrity": "sha1-wFJWtxJEIUZx9LCOwQitY7cO3bg=", - "dev": true - }, - "@webassemblyjs/helper-module-context": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-module-context/download/@webassemblyjs/helper-module-context-1.9.0.tgz", - "integrity": "sha1-JdiIS3aDmHGgimxvgGw5ee9xLwc=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-wasm-bytecode/download/@webassemblyjs/helper-wasm-bytecode-1.9.0.tgz?cache=0&sync_timestamp=1580600708901&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-wasm-bytecode%2Fdownload%2F%40webassemblyjs%2Fhelper-wasm-bytecode-1.9.0.tgz", - "integrity": "sha1-T+2L6sm4wU+MWLcNEk1UndH+V5A=", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/helper-wasm-section/download/@webassemblyjs/helper-wasm-section-1.9.0.tgz?cache=0&sync_timestamp=1580599464343&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fhelper-wasm-section%2Fdownload%2F%40webassemblyjs%2Fhelper-wasm-section-1.9.0.tgz", - "integrity": "sha1-WkE41aYpK6GLBMWuSXF+QWeWU0Y=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/ieee754/download/@webassemblyjs/ieee754-1.9.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fieee754%2Fdownload%2F%40webassemblyjs%2Fieee754-1.9.0.tgz", - "integrity": "sha1-Fceg+6roP7JhQ7us9tbfFwKtOeQ=", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/leb128/download/@webassemblyjs/leb128-1.9.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fleb128%2Fdownload%2F%40webassemblyjs%2Fleb128-1.9.0.tgz", - "integrity": "sha1-8Zygt2ptxVYjoJz/p2noOPoeHJU=", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/utf8/download/@webassemblyjs/utf8-1.9.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Futf8%2Fdownload%2F%40webassemblyjs%2Futf8-1.9.0.tgz", - "integrity": "sha1-BNM7Y2945qaBMifoJAL3Y3tiKas=", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-edit/download/@webassemblyjs/wasm-edit-1.9.0.tgz?cache=0&sync_timestamp=1580599461044&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwasm-edit%2Fdownload%2F%40webassemblyjs%2Fwasm-edit-1.9.0.tgz", - "integrity": "sha1-P+bXnT8PkiGDqoYALELdJWz+6c8=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/helper-wasm-section": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-opt": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "@webassemblyjs/wast-printer": "1.9.0" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-gen/download/@webassemblyjs/wasm-gen-1.9.0.tgz?cache=0&sync_timestamp=1580600714947&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwasm-gen%2Fdownload%2F%40webassemblyjs%2Fwasm-gen-1.9.0.tgz", - "integrity": "sha1-ULxw7Gje2OJ2OwGhQYv0NJGnpJw=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-opt/download/@webassemblyjs/wasm-opt-1.9.0.tgz?cache=0&sync_timestamp=1580600719192&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwasm-opt%2Fdownload%2F%40webassemblyjs%2Fwasm-opt-1.9.0.tgz", - "integrity": "sha1-IhEYHlsxMmRDzIES658LkChyGmE=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wasm-parser/download/@webassemblyjs/wasm-parser-1.9.0.tgz?cache=0&sync_timestamp=1580599463057&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwasm-parser%2Fdownload%2F%40webassemblyjs%2Fwasm-parser-1.9.0.tgz", - "integrity": "sha1-nUjkSCbfSmWYKUqmyHRp1kL/9l4=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" - } - }, - "@webassemblyjs/wast-parser": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wast-parser/download/@webassemblyjs/wast-parser-1.9.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwast-parser%2Fdownload%2F%40webassemblyjs%2Fwast-parser-1.9.0.tgz", - "integrity": "sha1-MDERXXmsW9JhVWzsw/qQo+9FGRQ=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/floating-point-hex-parser": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-code-frame": "1.9.0", - "@webassemblyjs/helper-fsm": "1.9.0", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.9.0", - "resolved": "https://registry.npm.taobao.org/@webassemblyjs/wast-printer/download/@webassemblyjs/wast-printer-1.9.0.tgz?cache=0&sync_timestamp=1580600723640&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40webassemblyjs%2Fwast-printer%2Fdownload%2F%40webassemblyjs%2Fwast-printer-1.9.0.tgz", - "integrity": "sha1-STXVTIX+9jewDOn1I3dFHQDUeJk=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/@xtuc/ieee754/download/@xtuc/ieee754-1.2.0.tgz", - "integrity": "sha1-7vAUoxRa5Hehy8AM0eVSM23Ot5A=", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npm.taobao.org/@xtuc/long/download/@xtuc/long-4.2.2.tgz", - "integrity": "sha1-0pHGpOl5ibXGHZrPOWrk/hM6cY0=", - "dev": true - }, - "abab": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/abab/download/abab-2.0.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fabab%2Fdownload%2Fabab-2.0.3.tgz", - "integrity": "sha1-Yj4gdeAustPyR15J+ZyRhGRnkHo=", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/abbrev/download/abbrev-1.1.1.tgz", - "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz", - "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", - "dev": true, - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "7.3.1", - "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-7.3.1.tgz?cache=0&sync_timestamp=1591869461226&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-7.3.1.tgz", - "integrity": "sha1-hQEHVNtTw/uvO56j4IOqXF0Uf/0=", - "dev": true - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npm.taobao.org/acorn-globals/download/acorn-globals-4.3.4.tgz", - "integrity": "sha1-n6GSat3BHJcwjE5m163Q1Awycuc=", - "dev": true, - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-6.4.1.tgz?cache=0&sync_timestamp=1591869461226&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-6.4.1.tgz", - "integrity": "sha1-Ux5Yuj9RudrLmmZGyk3r9bFMpHQ=", - "dev": true - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npm.taobao.org/acorn-walk/download/acorn-walk-6.2.0.tgz?cache=0&sync_timestamp=1592373525906&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-walk%2Fdownload%2Facorn-walk-6.2.0.tgz", - "integrity": "sha1-Ejy487hMIXHx9/slJhWxx4prGow=", - "dev": true - } - } - }, - "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/acorn-jsx/download/acorn-jsx-5.2.0.tgz", - "integrity": "sha1-TGYGkXPW/daO2FI5/CViJhgrLr4=", - "dev": true - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npm.taobao.org/acorn-walk/download/acorn-walk-7.2.0.tgz?cache=0&sync_timestamp=1592373525906&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-walk%2Fdownload%2Facorn-walk-7.2.0.tgz", - "integrity": "sha1-DeiJpgEgOQmw++B7iTjcIdLpZ7w=", - "dev": true - }, - "address": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/address/download/address-1.1.2.tgz", - "integrity": "sha1-vxEWycdYxRt6kz0pa3LCIe2UKLY=", - "dev": true - }, - "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/aggregate-error/download/aggregate-error-3.0.1.tgz", - "integrity": "sha1-2y/nJG5Tb0DZtUQqOeEX191qJOA=", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "dependencies": { - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/indent-string/download/indent-string-4.0.0.tgz", - "integrity": "sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE=", - "dev": true - } - } - }, - "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.2.tgz?cache=0&sync_timestamp=1593876933357&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.2.tgz", - "integrity": "sha1-xinF7O0XuvMUQ3kY0tqIyZ1ZWM0=", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/ajv-errors/download/ajv-errors-1.0.1.tgz", - "integrity": "sha1-81mGrOuRr63sQQL72FAUlQzvpk0=", - "dev": true - }, - "ajv-keywords": { - "version": "3.4.1", - "resolved": "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.4.1.tgz?cache=0&sync_timestamp=1594153583457&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv-keywords%2Fdownload%2Fajv-keywords-3.4.1.tgz", - "integrity": "sha1-75FuJxxkrBIXH9g4TqrmsjRYVNo=", - "dev": true - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/alphanum-sort/download/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/amdefine/download/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, - "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npm.taobao.org/ansi-colors/download/ansi-colors-3.2.4.tgz", - "integrity": "sha1-46PaS/uubIapwoViXeEkojQCb78=", - "dev": true - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/ansi-escapes/download/ansi-escapes-3.2.0.tgz?cache=0&sync_timestamp=1583072820951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-escapes%2Fdownload%2Fansi-escapes-3.2.0.tgz", - "integrity": "sha1-h4C5j/nb9WOBUtHx/lwde0RCl2s=", - "dev": true - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npm.taobao.org/ansi-html/download/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-2.1.1.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "requires": { - "color-convert": "^1.9.0" - } - }, - "ansi-to-html": { - "version": "0.6.14", - "resolved": "https://registry.npm.taobao.org/ansi-to-html/download/ansi-to-html-0.6.14.tgz", - "integrity": "sha1-Zf5tCLul3Z2zP0SiCuwzHgAQ2tg=", - "requires": { - "entities": "^1.1.2" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-2.0.0.tgz?cache=0&sync_timestamp=1569897341237&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fanymatch%2Fdownload%2Fanymatch-2.0.0.tgz", - "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "arch": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/arch/download/arch-2.1.2.tgz", - "integrity": "sha1-DFK75zRLtPomDEQ9LLrZwA/y8L8=", - "dev": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npm.taobao.org/are-we-there-yet/download/are-we-there-yet-1.1.5.tgz", - "integrity": "sha1-SzXClE8GKov82mZBB2A1D+nd/CE=", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npm.taobao.org/argparse/download/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/arr-diff/download/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/arr-flatten/download/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/arr-union/download/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/array-equal/download/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/array-find-index/download/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz?cache=0&sync_timestamp=1574313293899&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-flatten%2Fdownload%2Farray-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/array-uniq/download/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npm.taobao.org/asn1/download/asn1-0.2.4.tgz", - "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npm.taobao.org/asn1.js/download/asn1.js-4.10.1.tgz", - "integrity": "sha1-ucK/WAXx5kqt7tbfOiv6+1pz9aA=", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npm.taobao.org/assert/download/assert-1.5.0.tgz", - "integrity": "sha1-VcEJqvbgrv2z3EtxJAxwv1dLGOs=", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npm.taobao.org/util/download/util-0.10.3.tgz?cache=0&sync_timestamp=1588238331562&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futil%2Fdownload%2Futil-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/assign-symbols/download/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/astral-regex/download/astral-regex-1.0.0.tgz", - "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", - "dev": true - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npm.taobao.org/async/download/async-2.6.3.tgz", - "integrity": "sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8=", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/async-each/download/async-each-1.0.3.tgz", - "integrity": "sha1-tyfb+H12UWAvBvTUrDh/R9kbDL8=", - "dev": true - }, - "async-foreach": { - "version": "0.1.3", - "resolved": "https://registry.npm.taobao.org/async-foreach/download/async-foreach-0.1.3.tgz", - "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fasync-limiter%2Fdownload%2Fasync-limiter-1.0.1.tgz", - "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=", - "dev": true - }, - "async-validator": { - "version": "1.8.5", - "resolved": "https://registry.npm.taobao.org/async-validator/download/async-validator-1.8.5.tgz", - "integrity": "sha1-3D4I7B/Q3dtn5ghC8CwM0c7G1/A=", - "requires": { - "babel-runtime": "6.x" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/atob/download/atob-2.1.2.tgz", - "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k=", - "dev": true - }, - "autoprefixer": { - "version": "9.8.0", - "resolved": "https://registry.npm.taobao.org/autoprefixer/download/autoprefixer-9.8.0.tgz?cache=0&sync_timestamp=1594444685590&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fautoprefixer%2Fdownload%2Fautoprefixer-9.8.0.tgz", - "integrity": "sha1-aOLSvve6TDplQ29mLQpWp0HlZRE=", - "dev": true, - "requires": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001061", - "chalk": "^2.4.2", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.30", - "postcss-value-parser": "^4.1.0" - } - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.10.0", - "resolved": "https://registry.npm.taobao.org/aws4/download/aws4-1.10.0.tgz?cache=0&sync_timestamp=1590183310661&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faws4%2Fdownload%2Faws4-1.10.0.tgz", - "integrity": "sha1-oXs6jqgRBg501H0wYSJACtRJeuI=", - "dev": true - }, - "axios": { - "version": "0.19.2", - "resolved": "https://registry.npm.taobao.org/axios/download/axios-0.19.2.tgz?cache=0&sync_timestamp=1594827675434&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faxios%2Fdownload%2Faxios-0.19.2.tgz", - "integrity": "sha1-PqNsXYgY0NX4qKl6bTa4bNwAyyc=", - "requires": { - "follow-redirects": "1.5.10" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npm.taobao.org/babel-code-frame/download/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-2.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-1.1.3.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/js-tokens/download/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-2.0.0.tgz?cache=0&sync_timestamp=1569557271992&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "babel-core": { - "version": "7.0.0-bridge.0", - "resolved": "https://registry.npm.taobao.org/babel-core/download/babel-core-7.0.0-bridge.0.tgz", - "integrity": "sha1-laSS3dkPm06aSh2hTrM1uHtjTs4=", - "dev": true - }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz?cache=0&sync_timestamp=1582676223200&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-eslint%2Fdownload%2Fbabel-eslint-10.1.0.tgz", - "integrity": "sha1-aWjlaKkQt4+zd5zdi2rC9HmUMjI=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - } - }, - "babel-helper-vue-jsx-merge-props": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/babel-helper-vue-jsx-merge-props/download/babel-helper-vue-jsx-merge-props-2.0.3.tgz", - "integrity": "sha1-Iq69OzOQIyjlEyk6jkmSs4T58bY=" - }, - "babel-jest": { - "version": "26.0.1", - "resolved": "https://registry.npm.taobao.org/babel-jest/download/babel-jest-26.0.1.tgz?cache=0&sync_timestamp=1592926057142&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-jest%2Fdownload%2Fbabel-jest-26.0.1.tgz", - "integrity": "sha1-RQE5zktsFxdLE2QlvakYhcOXvEY=", - "dev": true, - "requires": { - "@jest/transform": "^26.0.1", - "@jest/types": "^26.0.1", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/transform": { - "version": "26.0.1", - "resolved": "https://registry.npm.taobao.org/@jest/transform/download/@jest/transform-26.0.1.tgz?cache=0&sync_timestamp=1592926445716&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ftransform%2Fdownload%2F%40jest%2Ftransform-26.0.1.tgz", - "integrity": "sha1-Dj7Ls0oRzUsggO0KnEhWzwzrBjk=", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.0.1", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.0.1", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - } - }, - "@jest/types": { - "version": "26.0.1", - "resolved": "https://registry.npm.taobao.org/@jest/types/download/@jest/types-26.0.1.tgz?cache=0&sync_timestamp=1592926441617&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ftypes%2Fdownload%2F%40jest%2Ftypes-26.0.1.tgz", - "integrity": "sha1-t4Mz+9ET+nrsjTneJPiN6GhtrGc=", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "15.0.5", - "resolved": "https://registry.npm.taobao.org/@types/yargs/download/@types/yargs-15.0.5.tgz", - "integrity": "sha1-lH6aZWFIO97prf/Jg+kaaQKvi3k=", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.2.1.tgz", - "integrity": "sha1-kK51xCTQCNJiTFvynq0xd+v881k=", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.1.tgz?cache=0&sync_timestamp=1569897341237&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fanymatch%2Fdownload%2Fanymatch-3.1.1.tgz", - "integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-istanbul/download/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha1-4VnM3Jr5XgtXDHW0Vzt8NNZx12U=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" - }, - "dependencies": { - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/@istanbuljs/load-nyc-config/download/@istanbuljs/load-nyc-config-1.1.0.tgz", - "integrity": "sha1-/T2x1Z7PfPEh6AZQu4ZxL5tV7O0=", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - } - }, - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/@istanbuljs/schema/download/@istanbuljs/schema-0.1.2.tgz", - "integrity": "sha1-JlIL8Jq+SlZEzVQU43ElqJVCQd0=", - "dev": true - } - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz", - "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-4.1.0.tgz", - "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz", - "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-4.1.0.tgz", - "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.1.3.tgz", - "integrity": "sha1-+3OHA66NL5/pAMM4Nt3r7ouX8j4=", - "dev": true, - "optional": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz", - "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/istanbul-lib-coverage/download/istanbul-lib-coverage-3.0.0.tgz?cache=0&sync_timestamp=1577062542104&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fistanbul-lib-coverage%2Fdownload%2Fistanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha1-9ZRKN8cLVQsCp4pcOyBVsoDOyOw=", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/istanbul-lib-instrument/download/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha1-hzxv/4l0UBGCIndGlqPyiQLXfB0=", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/@istanbuljs/schema/download/@istanbuljs/schema-0.1.2.tgz", - "integrity": "sha1-JlIL8Jq+SlZEzVQU43ElqJVCQd0=", - "dev": true - } - } - }, - "jest-haste-map": { - "version": "26.1.0", - "resolved": "https://registry.npm.taobao.org/jest-haste-map/download/jest-haste-map-26.1.0.tgz?cache=0&sync_timestamp=1592925338595&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-haste-map%2Fdownload%2Fjest-haste-map-26.1.0.tgz", - "integrity": "sha1-7zEgm+c/CbDZRF59IT4bU9DRR2o=", - "dev": true, - "requires": { - "@jest/types": "^26.1.0", - "@types/graceful-fs": "^4.1.2", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", - "graceful-fs": "^4.2.4", - "jest-serializer": "^26.1.0", - "jest-util": "^26.1.0", - "jest-worker": "^26.1.0", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7", - "which": "^2.0.2" - }, - "dependencies": { - "@jest/types": { - "version": "26.1.0", - "resolved": "https://registry.npm.taobao.org/@jest/types/download/@jest/types-26.1.0.tgz?cache=0&sync_timestamp=1592926441617&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ftypes%2Fdownload%2F%40jest%2Ftypes-26.1.0.tgz", - "integrity": "sha1-+K+qrusjtcrUndH3d5aJlB3LYFc=", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/graceful-fs": { - "version": "4.1.3", - "resolved": "https://registry.npm.taobao.org/@types/graceful-fs/download/@types/graceful-fs-4.1.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fgraceful-fs%2Fdownload%2F%40types%2Fgraceful-fs-4.1.3.tgz", - "integrity": "sha1-A5rzX+Jr7DUAPo2G0u6cWGNUNI8=", - "dev": true, - "requires": { - "@types/node": "*" - } - } - } - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npm.taobao.org/jest-regex-util/download/jest-regex-util-26.0.0.tgz", - "integrity": "sha1-0l5xhLNuOf1GbDvEG+CXHoIf7ig=", - "dev": true - }, - "jest-serializer": { - "version": "26.1.0", - "resolved": "https://registry.npm.taobao.org/jest-serializer/download/jest-serializer-26.1.0.tgz?cache=0&sync_timestamp=1592926443254&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-serializer%2Fdownload%2Fjest-serializer-26.1.0.tgz", - "integrity": "sha1-cqOUUx/JsI4XPcfSl0QKxhDZUCI=", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4" - } - }, - "jest-util": { - "version": "26.1.0", - "resolved": "https://registry.npm.taobao.org/jest-util/download/jest-util-26.1.0.tgz?cache=0&sync_timestamp=1592925342680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-util%2Fdownload%2Fjest-util-26.1.0.tgz", - "integrity": "sha1-gOhdS6gg3srPQaaRwgQtUnbl2Ng=", - "dev": true, - "requires": { - "@jest/types": "^26.1.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "dependencies": { - "@jest/types": { - "version": "26.1.0", - "resolved": "https://registry.npm.taobao.org/@jest/types/download/@jest/types-26.1.0.tgz?cache=0&sync_timestamp=1592926441617&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40jest%2Ftypes%2Fdownload%2F%40jest%2Ftypes-26.1.0.tgz", - "integrity": "sha1-+K+qrusjtcrUndH3d5aJlB3LYFc=", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - } - } - }, - "jest-worker": { - "version": "26.1.0", - "resolved": "https://registry.npm.taobao.org/jest-worker/download/jest-worker-26.1.0.tgz", - "integrity": "sha1-ZdVkGvdOCMzVYcJA59thKE+C8z0=", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz", - "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/micromatch/download/micromatch-4.0.2.tgz", - "integrity": "sha1-T8sJmb+fvC/L3SEvbWKbmlbDklk=", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-4.1.0.tgz", - "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz", - "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/resolve-from/download/resolve-from-5.0.0.tgz", - "integrity": "sha1-w1IlhD3493bfIcV1V7wIfp39/Gk=", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/slash/download/slash-3.0.0.tgz", - "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.1.0.tgz?cache=0&sync_timestamp=1569557271992&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.1.0.tgz", - "integrity": "sha1-aOMlkd9z4lrRxLSRCKLsUHliv9E=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/test-exclude/download/test-exclude-6.0.0.tgz", - "integrity": "sha1-BKhphmHYBepvopO2y55jrARO8V4=", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "dependencies": { - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/@istanbuljs/schema/download/@istanbuljs/schema-0.1.2.tgz", - "integrity": "sha1-JlIL8Jq+SlZEzVQU43ElqJVCQd0=", - "dev": true - } - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz", - "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz", - "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/write-file-atomic/download/write-file-atomic-3.0.3.tgz?cache=0&sync_timestamp=1582584103455&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwrite-file-atomic%2Fdownload%2Fwrite-file-atomic-3.0.3.tgz", - "integrity": "sha1-Vr1cWlxwSBzRnFcb05q5ZaXeVug=", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - }, - "dependencies": { - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npm.taobao.org/typedarray-to-buffer/download/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha1-qX7nqf9CaRufeD/xvFES/j/KkIA=", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - } - } - } - } - }, - "babel-loader": { - "version": "8.1.0", - "resolved": "https://registry.npm.taobao.org/babel-loader/download/babel-loader-8.1.0.tgz?cache=0&sync_timestamp=1584715959282&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-loader%2Fdownload%2Fbabel-loader-8.1.0.tgz", - "integrity": "sha1-xhHVESvVIJq+i5+oTD5NolJ18cM=", - "dev": true, - "requires": { - "find-cache-dir": "^2.1.0", - "loader-utils": "^1.4.0", - "mkdirp": "^0.5.3", - "pify": "^4.0.1", - "schema-utils": "^2.6.5" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", - "dev": true - } - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npm.taobao.org/babel-messages/download/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npm.taobao.org/babel-plugin-dynamic-import-node/download/babel-plugin-dynamic-import-node-2.3.3.tgz?cache=0&sync_timestamp=1587495874530&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-plugin-dynamic-import-node%2Fdownload%2Fbabel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha1-hP2hnJduxcbe/vV/lCez3vZuF6M=", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-istanbul/download/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha1-30reg9iXqS3wacTZolzyZxKTyFQ=", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" - } - }, - "babel-plugin-jest-hoist": { - "version": "26.1.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-jest-hoist/download/babel-plugin-jest-hoist-26.1.0.tgz?cache=0&sync_timestamp=1592926445554&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-plugin-jest-hoist%2Fdownload%2Fbabel-plugin-jest-hoist-26.1.0.tgz", - "integrity": "sha1-xqd02ggkeigoViCmTfrb0F3VIzo=", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npm.taobao.org/babel-plugin-transform-es2015-modules-commonjs/download/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha1-WKeThjqefKhwvcWogRF/+sJ9tvM=", - "dev": true, - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npm.taobao.org/babel-plugin-transform-strict-mode/download/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-polyfill": { - "version": "6.26.0", - "resolved": "https://registry.npm.taobao.org/babel-polyfill/download/babel-polyfill-6.26.0.tgz", - "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", - "requires": { - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "regenerator-runtime": "^0.10.5" - }, - "dependencies": { - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npm.taobao.org/core-js/download/core-js-2.6.11.tgz", - "integrity": "sha1-OIMUafmSK97Y7iHJ3EaYXgOZMIw=" - } - } - }, - "babel-preset-current-node-syntax": { - "version": "0.1.3", - "resolved": "https://registry.npm.taobao.org/babel-preset-current-node-syntax/download/babel-preset-current-node-syntax-0.1.3.tgz", - "integrity": "sha1-tLVHrN2/ljy6VVup+cu7cL/QRNo=", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "26.0.0", - "resolved": "https://registry.npm.taobao.org/babel-preset-jest/download/babel-preset-jest-26.0.0.tgz?cache=0&sync_timestamp=1592927135667&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-preset-jest%2Fdownload%2Fbabel-preset-jest-26.0.0.tgz", - "integrity": "sha1-HqyC9ROtNsTbLpJj18SFyCWx+qY=", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^26.0.0", - "babel-preset-current-node-syntax": "^0.1.2" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npm.taobao.org/babel-runtime/download/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npm.taobao.org/core-js/download/core-js-2.6.11.tgz", - "integrity": "sha1-OIMUafmSK97Y7iHJ3EaYXgOZMIw=" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.11.1.tgz?cache=0&sync_timestamp=1584052597708&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.11.1.tgz", - "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=" - } - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npm.taobao.org/babel-template/download/babel-template-6.26.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-template%2Fdownload%2Fbabel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npm.taobao.org/babel-traverse/download/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npm.taobao.org/globals/download/globals-9.18.0.tgz", - "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", - "dev": true - } - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npm.taobao.org/babel-types/download/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - }, - "dependencies": { - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-1.0.3.tgz?cache=0&sync_timestamp=1580550317222&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fto-fast-properties%2Fdownload%2Fto-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - } - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npm.taobao.org/babylon/download/babylon-6.18.0.tgz", - "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npm.taobao.org/base/download/base-0.11.2.tgz", - "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz", - "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", - "dev": true - } - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/base64-js/download/base64-js-1.3.1.tgz", - "integrity": "sha1-WOzoy3XdB+ce0IxzarxfrE2/jfE=", - "dev": true - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/batch/download/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bfj": { - "version": "6.1.2", - "resolved": "https://registry.npm.taobao.org/bfj/download/bfj-6.1.2.tgz", - "integrity": "sha1-MlyGGoIryzWKQceKM7jm4ght3n8=", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "check-types": "^8.0.3", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" - } - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz", - "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=", - "dev": true - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-1.13.1.tgz?cache=0&sync_timestamp=1593261627308&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbinary-extensions%2Fdownload%2Fbinary-extensions-1.13.1.tgz", - "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npm.taobao.org/bindings/download/bindings-1.5.0.tgz", - "integrity": "sha1-EDU8npRTNLwFEabZCzj7x8nFBN8=", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npm.taobao.org/bluebird/download/bluebird-3.7.2.tgz", - "integrity": "sha1-nyKcFb4nJFT/qXOs4NvueaGww28=", - "dev": true - }, - "bn.js": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-5.1.2.tgz", - "integrity": "sha1-yWhpAtPJoncp9DqxD515wgBNp7A=", - "dev": true - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npm.taobao.org/body-parser/download/body-parser-1.19.0.tgz", - "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", - "dev": true, - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npm.taobao.org/bonjour/download/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - }, - "dependencies": { - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/array-flatten/download/array-flatten-2.1.2.tgz?cache=0&sync_timestamp=1574313293899&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-flatten%2Fdownload%2Farray-flatten-2.1.2.tgz", - "integrity": "sha1-JO+AoowaiTYX4hSbDG0NeIKTsJk=", - "dev": true - } - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/boolbase/download/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npm.taobao.org/braces/download/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/brorand/download/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/browser-process-hrtime/download/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha1-PJtLfXgsgSHlbxAQbYTA0P/JRiY=", - "dev": true - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npm.taobao.org/browser-resolve/download/browser-resolve-1.11.3.tgz", - "integrity": "sha1-m3y7PQ9RDky4a9vXlhJNKLWJCvY=", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npm.taobao.org/resolve/download/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/browserify-aes/download/browserify-aes-1.2.0.tgz", - "integrity": "sha1-Mmc0ZC9APavDADIJhTu3CtQo70g=", - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/browserify-cipher/download/browserify-cipher-1.0.1.tgz", - "integrity": "sha1-jWR0wbhwv9q807z8wZNKEOlPFfA=", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/browserify-des/download/browserify-des-1.0.2.tgz", - "integrity": "sha1-OvTx9Zg5QDVy8cZiBDdfen9wPpw=", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/browserify-rsa/download/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "browserify-sign": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/browserify-sign/download/browserify-sign-4.2.0.tgz?cache=0&sync_timestamp=1589815280345&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbrowserify-sign%2Fdownload%2Fbrowserify-sign-4.2.0.tgz", - "integrity": "sha1-VF0LGwfmssmSEQgr8bEsznoLDhE=", - "dev": true, - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.2", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/browserify-zlib/download/browserify-zlib-0.2.0.tgz", - "integrity": "sha1-KGlFnZqjviRf6P4sofRuLn9U1z8=", - "dev": true, - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "4.13.0", - "resolved": "https://registry.npm.taobao.org/browserslist/download/browserslist-4.13.0.tgz?cache=0&sync_timestamp=1593912354155&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbrowserslist%2Fdownload%2Fbrowserslist-4.13.0.tgz", - "integrity": "sha1-QlVsugEeGwondbYRy6ao7KGOlA0=", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001093", - "electron-to-chromium": "^1.3.488", - "escalade": "^3.0.1", - "node-releases": "^1.1.58" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npm.taobao.org/bs-logger/download/bs-logger-0.2.6.tgz", - "integrity": "sha1-6302UwenLPl0zGzadraDVK0za9g=", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/bser/download/bser-2.1.1.tgz", - "integrity": "sha1-5nh9og7OnQeZhTPP2d5vXDj0vAU=", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npm.taobao.org/buffer/download/buffer-4.9.2.tgz?cache=0&sync_timestamp=1588713323419&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbuffer%2Fdownload%2Fbuffer-4.9.2.tgz", - "integrity": "sha1-Iw6tNEACmIZEhBqwJEr4xEu+Pvg=", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz", - "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=", - "dev": true - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/buffer-indexof/download/buffer-indexof-1.1.1.tgz", - "integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=", - "dev": true - }, - "buffer-json": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/buffer-json/download/buffer-json-2.0.0.tgz", - "integrity": "sha1-9z4TseQvGW/i/WfQAcfXEH7dfCM=", - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/buffer-xor/download/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/builtin-status-codes/download/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz", - "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=", - "dev": true - }, - "cacache": { - "version": "12.0.4", - "resolved": "https://registry.npm.taobao.org/cacache/download/cacache-12.0.4.tgz?cache=0&sync_timestamp=1594429684526&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcacache%2Fdownload%2Fcacache-12.0.4.tgz", - "integrity": "sha1-ZovL0QWutfHZL+JVcOyVJcj6pAw=", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/cache-base/download/cache-base-1.0.1.tgz", - "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cache-loader": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/cache-loader/download/cache-loader-4.1.0.tgz", - "integrity": "sha1-mUjK41OuwKH8ser9ojAIFuyFOH4=", - "dev": true, - "requires": { - "buffer-json": "^2.0.0", - "find-cache-dir": "^3.0.0", - "loader-utils": "^1.2.3", - "mkdirp": "^0.5.1", - "neo-async": "^2.6.1", - "schema-utils": "^2.0.0" - }, - "dependencies": { - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-3.3.1.tgz", - "integrity": "sha1-ibM/rUpGcNqpT4Vff74x1thP6IA=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-4.1.0.tgz", - "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz", - "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-3.1.0.tgz?cache=0&sync_timestamp=1587567693680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmake-dir%2Fdownload%2Fmake-dir-3.1.0.tgz", - "integrity": "sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8=", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-4.1.0.tgz", - "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz", - "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-4.2.0.tgz", - "integrity": "sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM=", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/call-me-maybe/download/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/caller-callsite/download/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/caller-path/download/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-3.1.0.tgz", - "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", - "dev": true - }, - "camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/camel-case/download/camel-case-3.0.0.tgz", - "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", - "dev": true, - "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz", - "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=" - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/camelcase-keys/download/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - } - } - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/caniuse-api/download/caniuse-api-3.0.0.tgz", - "integrity": "sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001103", - "resolved": "https://registry.npm.taobao.org/caniuse-lite/download/caniuse-lite-1.0.30001103.tgz?cache=0&sync_timestamp=1595136853682&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcaniuse-lite%2Fdownload%2Fcaniuse-lite-1.0.30001103.tgz", - "integrity": "sha1-/oFTbQdbl80BPUmIySEkGPqiiag=", - "dev": true - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/capture-exit/download/capture-exit-2.0.0.tgz", - "integrity": "sha1-+5U7+uvreB9iiYI52rtCbQilCaQ=", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, - "case-sensitive-paths-webpack-plugin": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/case-sensitive-paths-webpack-plugin/download/case-sensitive-paths-webpack-plugin-2.3.0.tgz", - "integrity": "sha1-I6xhPMmoVuT4j/i7c7u16YmCXPc=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-2.4.2.tgz", - "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1569557271992&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz", - "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npm.taobao.org/chardet/download/chardet-0.7.0.tgz?cache=0&sync_timestamp=1594010664806&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchardet%2Fdownload%2Fchardet-0.7.0.tgz", - "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", - "dev": true - }, - "check-types": { - "version": "8.0.3", - "resolved": "https://registry.npm.taobao.org/check-types/download/check-types-8.0.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcheck-types%2Fdownload%2Fcheck-types-8.0.3.tgz", - "integrity": "sha1-M1bMoZyIlUTy16le1JzlCKDs9VI=", - "dev": true - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npm.taobao.org/chokidar/download/chokidar-2.1.8.tgz?cache=0&sync_timestamp=1594864807174&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchokidar%2Fdownload%2Fchokidar-2.1.8.tgz", - "integrity": "sha1-gEs6e2qZNYw8XGHnHYco8EHP+Rc=", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/chownr/download/chownr-1.1.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchownr%2Fdownload%2Fchownr-1.1.4.tgz", - "integrity": "sha1-b8nXtC0ypYNZYzdmbn0ICE2izGs=", - "dev": true - }, - "chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/chrome-trace-event/download/chrome-trace-event-1.0.2.tgz", - "integrity": "sha1-I0CQ7pfH1K0aLEvq4nUF3v/GCKQ=", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ci-info/download/ci-info-2.0.0.tgz", - "integrity": "sha1-Z6npZL4xpR4V5QENWObxKDQAL0Y=", - "dev": true - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/cipher-base/download/cipher-base-1.0.4.tgz", - "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz", - "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npm.taobao.org/clean-css/download/clean-css-4.2.3.tgz", - "integrity": "sha1-UHtd59l7SO5T2ErbAWD/YhY4D3g=", - "dev": true, - "requires": { - "source-map": "~0.6.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/clean-stack/download/clean-stack-2.2.0.tgz?cache=0&sync_timestamp=1592035231370&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fclean-stack%2Fdownload%2Fclean-stack-2.2.0.tgz", - "integrity": "sha1-7oRy27Ep5yezHooQpCfe6d/kAIs=", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/cli-cursor/download/cli-cursor-3.1.0.tgz", - "integrity": "sha1-JkMFp65JDR0Dvwybp8kl0XU68wc=", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-highlight": { - "version": "2.1.4", - "resolved": "https://registry.npm.taobao.org/cli-highlight/download/cli-highlight-2.1.4.tgz?cache=0&sync_timestamp=1573948719956&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcli-highlight%2Fdownload%2Fcli-highlight-2.1.4.tgz", - "integrity": "sha1-CYy2Qs8X9CrcHBFF4H+WDsTXUis=", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "highlight.js": "^9.6.0", - "mz": "^2.4.0", - "parse5": "^5.1.1", - "parse5-htmlparser2-tree-adapter": "^5.1.1", - "yargs": "^15.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-5.0.0.tgz", - "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.2.1.tgz", - "integrity": "sha1-kK51xCTQCNJiTFvynq0xd+v881k=", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-3.0.0.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-3.0.0.tgz", - "integrity": "sha1-P3PCv1JlkfV0zEksUeJFY0n4ROQ=", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-6.0.0.tgz?cache=0&sync_timestamp=1573943458671&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-6.0.0.tgz", - "integrity": "sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE=", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-8.0.0.tgz", - "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-4.1.0.tgz", - "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz", - "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-4.1.0.tgz", - "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz", - "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-4.2.0.tgz", - "integrity": "sha1-lSGCxGzHssMT0VluYjmSvRY7crU=", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-6.0.0.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-6.0.0.tgz", - "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.1.0.tgz?cache=0&sync_timestamp=1569557271992&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.1.0.tgz", - "integrity": "sha1-aOMlkd9z4lrRxLSRCKLsUHliv9E=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz", - "integrity": "sha1-6Tk7oHEC5skaOyIUePAlfNKFblM=", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npm.taobao.org/yargs/download/yargs-15.4.1.tgz?cache=0&sync_timestamp=1594421142336&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-15.4.1.tgz", - "integrity": "sha1-DYehbeAa7p2L7Cv7909nhRcw9Pg=", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-18.1.3.tgz?cache=0&sync_timestamp=1595125126126&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-18.1.3.tgz", - "integrity": "sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A=", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "cli-spinners": { - "version": "2.4.0", - "resolved": "https://registry.npm.taobao.org/cli-spinners/download/cli-spinners-2.4.0.tgz?cache=0&sync_timestamp=1595080377121&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcli-spinners%2Fdownload%2Fcli-spinners-2.4.0.tgz", - "integrity": "sha1-xiVtsha4eM+6RyDnGc7Hz3JoXX8=", - "dev": true - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/cli-width/download/cli-width-2.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcli-width%2Fdownload%2Fcli-width-2.2.1.tgz", - "integrity": "sha1-sEM9C06chH7xiGik7xb9X8gnHEg=", - "dev": true - }, - "clipboardy": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/clipboardy/download/clipboardy-2.3.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fclipboardy%2Fdownload%2Fclipboardy-2.3.0.tgz", - "integrity": "sha1-PCkDZQxo5GqRs4iYW8J3QofbopA=", - "dev": true, - "requires": { - "arch": "^2.1.1", - "execa": "^1.0.0", - "is-wsl": "^2.1.1" - }, - "dependencies": { - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/is-wsl/download/is-wsl-2.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-wsl%2Fdownload%2Fis-wsl-2.2.0.tgz", - "integrity": "sha1-dKTHbnfKn9P5MvKQwX6jJs0VcnE=", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - } - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-5.0.0.tgz?cache=0&sync_timestamp=1573943458671&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-5.0.0.tgz", - "integrity": "sha1-3u/P2y6AB4SqNPRvoI4GhRx7u8U=", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/clone/download/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/clone-deep/download/clone-deep-4.0.1.tgz", - "integrity": "sha1-wZ/Zvbv4WUK0/ZechNz31fB8I4c=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz", - "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", - "dev": true - } - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/coa/download/coa-2.0.2.tgz", - "integrity": "sha1-Q/bCEVG07yv1cYfbDXPeIp4+fsM=", - "dev": true, - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/code-point-at/download/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "codemirror": { - "version": "5.54.0", - "resolved": "https://registry.npm.taobao.org/codemirror/download/codemirror-5.54.0.tgz?cache=0&sync_timestamp=1592747787602&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcodemirror%2Fdownload%2Fcodemirror-5.54.0.tgz", - "integrity": "sha1-grat9mKynut7hn/ng51J4l5KCzg=" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/color/download/color-3.1.2.tgz", - "integrity": "sha1-aBSOf4XUGtdknF+oyBBvCY0inhA=", - "dev": true, - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz", - "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", - "requires": { - "color-name": "1.1.3" - }, - "dependencies": { - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - } - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true - }, - "color-string": { - "version": "1.5.3", - "resolved": "https://registry.npm.taobao.org/color-string/download/color-string-1.5.3.tgz", - "integrity": "sha1-ybvF8BtYtUkvPWhXRZy2WQziBMw=", - "dev": true, - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.8.tgz", - "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1592632050401&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz", - "integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz", - "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npm.taobao.org/compressible/download/compressible-2.0.18.tgz", - "integrity": "sha1-r1PMprBw1MPAdQ+9dyhqbXzEb7o=", - "dev": true, - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npm.taobao.org/compression/download/compression-1.7.4.tgz", - "integrity": "sha1-lVI+/xcMpXwpoMpB5v4TH0Hlu48=", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz?cache=0&sync_timestamp=1589129378619&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", - "dev": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npm.taobao.org/concat-stream/download/concat-stream-1.6.2.tgz", - "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "condense-newlines": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/condense-newlines/download/condense-newlines-0.2.1.tgz", - "integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-whitespace": "^0.3.0", - "kind-of": "^3.0.2" - } - }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npm.taobao.org/config-chain/download/config-chain-1.1.12.tgz", - "integrity": "sha1-D96NCRIA616AjK8l/mGMAvSOTvo=", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npm.taobao.org/connect-history-api-fallback/download/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha1-izIIk1kwjRERFdgcrT/Oq4iPl7w=", - "dev": true - }, - "console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/console-browserify/download/console-browserify-1.2.0.tgz", - "integrity": "sha1-ZwY871fOts9Jk6KrOlWECujEkzY=", - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/console-control-strings/download/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "consolidate": { - "version": "0.15.1", - "resolved": "https://registry.npm.taobao.org/consolidate/download/consolidate-0.15.1.tgz", - "integrity": "sha1-IasEMjXHGgfUXZqtmFk7DbpWurc=", - "dev": true, - "requires": { - "bluebird": "^3.1.1" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/constants-browserify/download/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.3.tgz", - "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", - "dev": true, - "requires": { - "safe-buffer": "5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz?cache=0&sync_timestamp=1589129378619&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", - "dev": true - } - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", - "dev": true - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.7.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fconvert-source-map%2Fdownload%2Fconvert-source-map-1.7.0.tgz", - "integrity": "sha1-F6LLiC1/d9NJBYXizmxSRCSjpEI=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz?cache=0&sync_timestamp=1589129378619&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", - "dev": true - } - } - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/cookie/download/cookie-0.4.0.tgz?cache=0&sync_timestamp=1587525873712&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcookie%2Fdownload%2Fcookie-0.4.0.tgz", - "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/copy-concurrently/download/copy-concurrently-1.0.5.tgz", - "integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/aproba/download/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", - "dev": true - } - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "copy-webpack-plugin": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/copy-webpack-plugin/download/copy-webpack-plugin-5.1.1.tgz?cache=0&sync_timestamp=1593550572650&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcopy-webpack-plugin%2Fdownload%2Fcopy-webpack-plugin-5.1.1.tgz", - "integrity": "sha1-VIGgPeoRI9iKmIxv+LeCRyFPC4g=", - "dev": true, - "requires": { - "cacache": "^12.0.3", - "find-cache-dir": "^2.1.0", - "glob-parent": "^3.1.0", - "globby": "^7.1.1", - "is-glob": "^4.0.1", - "loader-utils": "^1.2.3", - "minimatch": "^3.0.4", - "normalize-path": "^3.0.0", - "p-limit": "^2.2.1", - "schema-utils": "^1.0.0", - "serialize-javascript": "^2.1.2", - "webpack-log": "^2.0.0" - }, - "dependencies": { - "globby": { - "version": "7.1.1", - "resolved": "https://registry.npm.taobao.org/globby/download/globby-7.1.1.tgz", - "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - } - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npm.taobao.org/ignore/download/ignore-3.3.10.tgz", - "integrity": "sha1-Cpf7h2mG6AgcYxFg+PnziRV/AEM=", - "dev": true - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "serialize-javascript": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-2.1.2.tgz", - "integrity": "sha1-7OxTsOAxe9yV73arcHS3OEeF+mE=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/slash/download/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - } - } - }, - "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npm.taobao.org/core-js/download/core-js-3.6.5.tgz", - "integrity": "sha1-c5XcJzrzf7LlDpvT2f6EEoUjHRo=" - }, - "core-js-compat": { - "version": "3.6.5", - "resolved": "https://registry.npm.taobao.org/core-js-compat/download/core-js-compat-3.6.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js-compat%2Fdownload%2Fcore-js-compat-3.6.5.tgz", - "integrity": "sha1-KlHZpOJd/W5pAlGqgfmePAVIHxw=", - "dev": true, - "requires": { - "browserslist": "^4.8.5", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.0.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.0.0.tgz", - "integrity": "sha1-XzyjV2HkfgWyBsba/yz4FPAxa44=", - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npm.taobao.org/cosmiconfig/download/cosmiconfig-5.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcosmiconfig%2Fdownload%2Fcosmiconfig-5.2.1.tgz", - "integrity": "sha1-BA9yaAnFked6F8CjYmykW08Wixo=", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "dependencies": { - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/import-fresh/download/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - } - } - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/create-ecdh/download/create-ecdh-4.0.3.tgz", - "integrity": "sha1-yREbbzMEXEaX8UR4f5JUzcd8Rf8=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/create-hash/download/create-hash-1.2.0.tgz", - "integrity": "sha1-iJB4rxGmN1a8+1m9IhmWvjqe8ZY=", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npm.taobao.org/create-hmac/download/create-hmac-1.1.7.tgz", - "integrity": "sha1-aRcMeLOrlXFHsriwRXLkfq0iQ/8=", - "dev": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-env": { - "version": "7.0.2", - "resolved": "https://registry.npm.taobao.org/cross-env/download/cross-env-7.0.2.tgz", - "integrity": "sha1-vV7TEzmpOjQYrE88qco0Awgq5fk=", - "requires": { - "cross-spawn": "^7.0.1" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-7.0.3.tgz?cache=0&sync_timestamp=1590448522710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-spawn%2Fdownload%2Fcross-spawn-7.0.3.tgz", - "integrity": "sha1-9zqFudXUHQRVUcF34ogtSshXKKY=", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-3.1.1.tgz", - "integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-2.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshebang-command%2Fdownload%2Fshebang-command-2.0.0.tgz", - "integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-3.0.0.tgz", - "integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=" - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz", - "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-5.1.0.tgz?cache=0&sync_timestamp=1590448522710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-spawn%2Fdownload%2Fcross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npm.taobao.org/crypto-browserify/download/crypto-browserify-3.12.0.tgz", - "integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "css": { - "version": "2.2.4", - "resolved": "https://registry.npm.taobao.org/css/download/css-2.2.4.tgz?cache=0&sync_timestamp=1593663587907&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcss%2Fdownload%2Fcss-2.2.4.tgz", - "integrity": "sha1-xkZ1XHOXHyu6amAeLPL9cbEpiSk=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "source-map": "^0.6.1", - "source-map-resolve": "^0.5.2", - "urix": "^0.1.0" - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npm.taobao.org/css-color-names/download/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true - }, - "css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/css-declaration-sorter/download/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha1-wZiUD2OnbX42wecQGLABchBUyyI=", - "dev": true, - "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - } - }, - "css-loader": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/css-loader/download/css-loader-3.6.0.tgz?cache=0&sync_timestamp=1592056888388&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcss-loader%2Fdownload%2Fcss-loader-3.6.0.tgz", - "integrity": "sha1-Lkssfm4tJ/jI8o9hv/zS5ske9kU=", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^2.7.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/css-select/download/css-select-2.1.0.tgz", - "integrity": "sha1-ajRlM1ZjWTSoG6ymjQJVQyEF2+8=", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/css-select-base-adapter/download/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha1-Oy/0lyzDYquIVhUHqVQIoUMhNdc=", - "dev": true - }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npm.taobao.org/css-tree/download/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha1-mL69YsTB2flg7DQM+fdSLjBwmiI=", - "dev": true, - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - } - }, - "css-what": { - "version": "3.3.0", - "resolved": "https://registry.npm.taobao.org/css-what/download/css-what-3.3.0.tgz", - "integrity": "sha1-EP7Glqns4uWRrHctdZqsq6w4zTk=", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/cssesc/download/cssesc-3.0.0.tgz", - "integrity": "sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4=", - "dev": true - }, - "cssnano": { - "version": "4.1.10", - "resolved": "https://registry.npm.taobao.org/cssnano/download/cssnano-4.1.10.tgz", - "integrity": "sha1-CsQfCxPRPUZUh+ERt3jULaYxuLI=", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.7", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "cssnano-preset-default": { - "version": "4.0.7", - "resolved": "https://registry.npm.taobao.org/cssnano-preset-default/download/cssnano-preset-default-4.0.7.tgz", - "integrity": "sha1-UexmLM/KD4izltzZZ5zbkxvhf3Y=", - "dev": true, - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.2", - "postcss-unique-selectors": "^4.0.1" - } - }, - "cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/cssnano-util-get-arguments/download/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "dev": true - }, - "cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/cssnano-util-get-match/download/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "dev": true - }, - "cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/cssnano-util-raw-cache/download/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha1-sm1f1fcqEd/np4RvtMZyYPlr8oI=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/cssnano-util-same-parent/download/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha1-V0CC+yhZ0ttDOFWDXZqEVuoYu/M=", - "dev": true - }, - "csso": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/csso/download/csso-4.0.3.tgz?cache=0&sync_timestamp=1585052130344&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcsso%2Fdownload%2Fcsso-4.0.3.tgz", - "integrity": "sha1-DZmF3IUsfMKyys+74QeQFNGo6QM=", - "dev": true, - "requires": { - "css-tree": "1.0.0-alpha.39" - }, - "dependencies": { - "css-tree": { - "version": "1.0.0-alpha.39", - "resolved": "https://registry.npm.taobao.org/css-tree/download/css-tree-1.0.0-alpha.39.tgz", - "integrity": "sha1-K/8//huz93bPfu/ZHuXLp3oUnus=", - "dev": true, - "requires": { - "mdn-data": "2.0.6", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/mdn-data/download/mdn-data-2.0.6.tgz?cache=0&sync_timestamp=1593510420945&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmdn-data%2Fdownload%2Fmdn-data-2.0.6.tgz", - "integrity": "sha1-hS3GD8ql2qLoz2yRicRA7T4EKXg=", - "dev": true - } - } - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npm.taobao.org/cssom/download/cssom-0.3.8.tgz", - "integrity": "sha1-nxJ29bK0Y/IRTT8sdSUK+MGjb0o=", - "dev": true - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/cssstyle/download/cssstyle-1.4.0.tgz?cache=0&sync_timestamp=1588172192426&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcssstyle%2Fdownload%2Fcssstyle-1.4.0.tgz", - "integrity": "sha1-nTEyginTxWXGHlhrAgQaKPzNzPE=", - "dev": true, - "requires": { - "cssom": "0.3.x" - } - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npm.taobao.org/currently-unhandled/download/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "^1.0.1" - } - }, - "cyclist": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/cyclist/download/cyclist-1.0.1.tgz", - "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/data-urls/download/data-urls-1.1.0.tgz", - "integrity": "sha1-Fe4Fgrql4iu1nHcUDaj5x2lju/4=", - "dev": true, - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - }, - "dependencies": { - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/whatwg-url/download/whatwg-url-7.1.0.tgz", - "integrity": "sha1-wsSS8eymEpiO/T0iZr4bn8YXDQY=", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "dayjs": { - "version": "1.8.28", - "resolved": "https://registry.npm.taobao.org/dayjs/download/dayjs-1.8.28.tgz?cache=0&sync_timestamp=1593707172703&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdayjs%2Fdownload%2Fdayjs-1.8.28.tgz", - "integrity": "sha1-N6piAd9IPQiWRctsj2zvbwxNvAc=" - }, - "de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz", - "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/decode-uri-component/download/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/deep-equal/download/deep-equal-1.1.1.tgz?cache=0&sync_timestamp=1590392787863&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdeep-equal%2Fdownload%2Fdeep-equal-1.1.1.tgz", - "integrity": "sha1-tcmMlCzv+vfLBR4k4UNKJaLmB2o=", - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npm.taobao.org/deep-is/download/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deepmerge": { - "version": "1.5.2", - "resolved": "https://registry.npm.taobao.org/deepmerge/download/deepmerge-1.5.2.tgz?cache=0&sync_timestamp=1572279720382&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdeepmerge%2Fdownload%2Fdeepmerge-1.5.2.tgz", - "integrity": "sha1-EEmdhohEza1P7ghC34x/bwyVp1M=" - }, - "default-gateway": { - "version": "5.0.5", - "resolved": "https://registry.npm.taobao.org/default-gateway/download/default-gateway-5.0.5.tgz", - "integrity": "sha1-T9a9XShV05s0zFpZUFSG6ar8mxA=", - "dev": true, - "requires": { - "execa": "^3.3.0" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-7.0.3.tgz?cache=0&sync_timestamp=1590448522710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-spawn%2Fdownload%2Fcross-spawn-7.0.3.tgz", - "integrity": "sha1-9zqFudXUHQRVUcF34ogtSshXKKY=", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "execa": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/execa/download/execa-3.4.0.tgz?cache=0&sync_timestamp=1594145085955&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexeca%2Fdownload%2Fexeca-3.4.0.tgz", - "integrity": "sha1-wI7UVQ72XYWPrCaf/IVyRG8364k=", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "p-finally": "^2.0.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-5.1.0.tgz", - "integrity": "sha1-ASA83JJZf5uQkGfD5lbMH008Tck=", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-stream/download/is-stream-2.0.0.tgz", - "integrity": "sha1-venDJoDW+uBBKdasnZIc54FfeOM=", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-4.0.1.tgz", - "integrity": "sha1-t+zR5e1T2o43pV4cImnguX7XSOo=", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "p-finally": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/p-finally/download/p-finally-2.0.1.tgz", - "integrity": "sha1-vW/KqcVZoJa2gIBvTWV7Pw8kBWE=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-3.1.1.tgz", - "integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-2.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshebang-command%2Fdownload%2Fshebang-command-2.0.0.tgz", - "integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-3.0.0.tgz", - "integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz", - "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/defaults/download/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, - "requires": { - "clone": "^1.0.2" - }, - "dependencies": { - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/clone/download/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - } - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/define-properties/download/define-properties-1.1.3.tgz", - "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-2.0.2.tgz", - "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz", - "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", - "dev": true - } - } - }, - "del": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/del/download/del-4.1.1.tgz", - "integrity": "sha1-no8RciLqRKMf86FWwEm5kFKp8LQ=", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "dependencies": { - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npm.taobao.org/globby/download/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/p-map/download/p-map-2.1.0.tgz", - "integrity": "sha1-MQko/u+cnsxltosXaTAYpmXOoXU=", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", - "dev": true - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/delegates/download/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/des.js/download/des.js-1.0.1.tgz", - "integrity": "sha1-U4IULhvcU/hdhtU+X0qn3rkeCEM=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/detect-newline/download/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "dev": true - }, - "detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/detect-node/download/detect-node-2.0.4.tgz", - "integrity": "sha1-AU7o+PZpxcWAI9pkuBecCDooxGw=", - "dev": true - }, - "diff-match-patch": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/diff-match-patch/download/diff-match-patch-1.0.5.tgz", - "integrity": "sha1-q7WE1fEM0Rlt/FWqA3AVkq4/ezc=" - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/diff-sequences/download/diff-sequences-24.9.0.tgz", - "integrity": "sha1-VxXWJE4qpl9Iu6C8ly2wsLEelbU=", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npm.taobao.org/diffie-hellman/download/diffie-hellman-5.0.3.tgz", - "integrity": "sha1-QOjumPVaIUlgcUaSHGPhrl89KHU=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npm.taobao.org/dir-glob/download/dir-glob-2.2.2.tgz", - "integrity": "sha1-+gnwaUFTyJGLGLoN6vrpR2n8UMQ=", - "dev": true, - "requires": { - "path-type": "^3.0.0" - } - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/dns-equal/download/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "dns-packet": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/dns-packet/download/dns-packet-1.3.1.tgz", - "integrity": "sha1-EqpCaYEHW+UAuRDu3NC0fdfe2lo=", - "dev": true, - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/dns-txt/download/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/doctrine/download/doctrine-3.0.0.tgz", - "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/dom-converter/download/dom-converter-0.2.0.tgz", - "integrity": "sha1-ZyGp2u4uKTaClVtq/kFncWJ7t2g=", - "dev": true, - "requires": { - "utila": "~0.4" - } - }, - "dom-event-types": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/dom-event-types/download/dom-event-types-1.0.0.tgz", - "integrity": "sha1-WDCgop4b+Df+UKcM2ApZcjKBPK4=", - "dev": true - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npm.taobao.org/dom-serializer/download/dom-serializer-0.2.2.tgz", - "integrity": "sha1-GvuB9TNxcXXUeGVd68XjMtn5u1E=", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/domelementtype/download/domelementtype-2.0.1.tgz", - "integrity": "sha1-H4vf6R9aeAYydOgDtL3O326U+U0=", - "dev": true - }, - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/entities/download/entities-2.0.3.tgz?cache=0&sync_timestamp=1591227405887&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fentities%2Fdownload%2Fentities-2.0.3.tgz", - "integrity": "sha1-XEh+V0Krk8Fau12iJ1m4WQ7AO38=", - "dev": true - } - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/domain-browser/download/domain-browser-1.2.0.tgz?cache=0&sync_timestamp=1593752811901&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomain-browser%2Fdownload%2Fdomain-browser-1.2.0.tgz", - "integrity": "sha1-PTH1AZGmdJ3RN1p/Ui6CPULlTto=", - "dev": true - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/domelementtype/download/domelementtype-1.3.1.tgz", - "integrity": "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8=", - "dev": true - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/domexception/download/domexception-1.0.1.tgz", - "integrity": "sha1-k3RCZEymoxJh7zbj7Gd/6AVYLJA=", - "dev": true, - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npm.taobao.org/domhandler/download/domhandler-2.4.2.tgz", - "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npm.taobao.org/domutils/download/domutils-1.7.0.tgz?cache=0&sync_timestamp=1589053312321&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomutils%2Fdownload%2Fdomutils-1.7.0.tgz", - "integrity": "sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo=", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "dotenv": { - "version": "8.2.0", - "resolved": "https://registry.npm.taobao.org/dotenv/download/dotenv-8.2.0.tgz", - "integrity": "sha1-l+YZJZradQ7qPk6j4mvO6lQksWo=", - "dev": true - }, - "dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/dotenv-expand/download/dotenv-expand-5.1.0.tgz", - "integrity": "sha1-P7rwIL/XlIhAcuomsel5HUWmKfA=", - "dev": true - }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npm.taobao.org/duplexify/download/duplexify-3.7.1.tgz", - "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "easy-stack": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/easy-stack/download/easy-stack-1.0.0.tgz", - "integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "echarts": { - "version": "4.8.0", - "resolved": "https://registry.npm.taobao.org/echarts/download/echarts-4.8.0.tgz", - "integrity": "sha1-ssHPuSKbE9No7hBPyO6mALV01MQ=", - "requires": { - "zrender": "4.3.1" - } - }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npm.taobao.org/editorconfig/download/editorconfig-0.15.3.tgz", - "integrity": "sha1-vvhMTnX7jcsM5c7o79UcFZmb78U=", - "dev": true, - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "ejs": { - "version": "2.7.4", - "resolved": "https://registry.npm.taobao.org/ejs/download/ejs-2.7.4.tgz?cache=0&sync_timestamp=1589699694627&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fejs%2Fdownload%2Fejs-2.7.4.tgz", - "integrity": "sha1-SGYSh1c9zFPjZsehrlLDoSDuybo=", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.501", - "resolved": "https://registry.npm.taobao.org/electron-to-chromium/download/electron-to-chromium-1.3.501.tgz?cache=0&sync_timestamp=1595146874059&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Felectron-to-chromium%2Fdownload%2Felectron-to-chromium-1.3.501.tgz", - "integrity": "sha1-+qF6LLAQXuMNXhyofq59joXdMXU=", - "dev": true - }, - "element-ui": { - "version": "2.13.2", - "resolved": "https://registry.npm.taobao.org/element-ui/download/element-ui-2.13.2.tgz?cache=0&sync_timestamp=1589795216634&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Felement-ui%2Fdownload%2Felement-ui-2.13.2.tgz", - "integrity": "sha1-WCv0eqqqr+I+oZWPriF6aHrQZEc=", - "requires": { - "async-validator": "~1.8.1", - "babel-helper-vue-jsx-merge-props": "^2.0.0", - "deepmerge": "^1.2.0", - "normalize-wheel": "^1.0.1", - "resize-observer-polyfill": "^1.5.0", - "throttle-debounce": "^1.0.1" - } - }, - "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npm.taobao.org/elliptic/download/elliptic-6.5.3.tgz?cache=0&sync_timestamp=1592492791633&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Felliptic%2Fdownload%2Felliptic-6.5.3.tgz", - "integrity": "sha1-y1nrLv2vc6C9eMzXAVpirW4Pk9Y=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz", - "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=" - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz", - "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang=", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npm.taobao.org/end-of-stream/download/end-of-stream-1.4.4.tgz?cache=0&sync_timestamp=1569416272686&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fend-of-stream%2Fdownload%2Fend-of-stream-1.4.4.tgz", - "integrity": "sha1-WuZKX0UFe682JuwU2gyl5LJDHrA=", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/enhanced-resolve/download/enhanced-resolve-4.3.0.tgz?cache=0&sync_timestamp=1594972208431&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenhanced-resolve%2Fdownload%2Fenhanced-resolve-4.3.0.tgz", - "integrity": "sha1-O4BvO/r8HsfeaVUe+TzKRsFwQSY=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "dependencies": { - "memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npm.taobao.org/memory-fs/download/memory-fs-0.5.0.tgz", - "integrity": "sha1-MkwBKIuIZSlm0WHbd4OHIIRajjw=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - } - } - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/entities/download/entities-1.1.2.tgz?cache=0&sync_timestamp=1591227405887&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fentities%2Fdownload%2Fentities-1.1.2.tgz", - "integrity": "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY=" - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npm.taobao.org/errno/download/errno-0.1.7.tgz", - "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/error-ex/download/error-ex-1.3.2.tgz", - "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "error-stack-parser": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/error-stack-parser/download/error-stack-parser-2.0.6.tgz?cache=0&sync_timestamp=1578288503034&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ferror-stack-parser%2Fdownload%2Ferror-stack-parser-2.0.6.tgz", - "integrity": "sha1-WpmnB716TFinl5AtSNgoA+3mqtg=", - "dev": true, - "requires": { - "stackframe": "^1.1.1" - } - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npm.taobao.org/es-abstract/download/es-abstract-1.17.6.tgz?cache=0&sync_timestamp=1592109139084&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fes-abstract%2Fdownload%2Fes-abstract-1.17.6.tgz", - "integrity": "sha1-kUIHFweFeyysx7iey2cDFsPi1So=", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npm.taobao.org/es-to-primitive/download/es-to-primitive-1.2.1.tgz?cache=0&sync_timestamp=1573280885098&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fes-to-primitive%2Fdownload%2Fes-to-primitive-1.2.1.tgz", - "integrity": "sha1-5VzUyc3BiLzvsDs2bHNjI/xciYo=", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/escalade/download/escalade-3.0.2.tgz?cache=0&sync_timestamp=1594742958135&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescalade%2Fdownload%2Fescalade-3.0.2.tgz", - "integrity": "sha1-algNcO24eIDyK0yR0NVgeN9pYsQ=", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npm.taobao.org/escodegen/download/escodegen-1.14.3.tgz?cache=0&sync_timestamp=1592866436888&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescodegen%2Fdownload%2Fescodegen-1.14.3.tgz", - "integrity": "sha1-TnuB+6YVgdyXWC7XjKt/Do1j9QM=", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "eslint": { - "version": "6.8.0", - "resolved": "https://registry.npm.taobao.org/eslint/download/eslint-6.8.0.tgz?cache=0&sync_timestamp=1595098436203&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint%2Fdownload%2Feslint-6.8.0.tgz", - "integrity": "sha1-YiYtZylzn5J1cjgkMC+yJ8jJP/s=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-6.0.5.tgz?cache=0&sync_timestamp=1590448522710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-spawn%2Fdownload%2Fcross-spawn-6.0.5.tgz", - "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", - "dev": true - } - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-5.1.1.tgz", - "integrity": "sha1-tsHvQXxOVmPqSY8cRa+saRa7wik=", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npm.taobao.org/globals/download/globals-12.4.0.tgz", - "integrity": "sha1-oYgTV2pBsAokqX5/gVkYwuGZJfg=", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - }, - "dependencies": { - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npm.taobao.org/type-fest/download/type-fest-0.8.1.tgz?cache=0&sync_timestamp=1593290909259&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftype-fest%2Fdownload%2Ftype-fest-0.8.1.tgz", - "integrity": "sha1-CeJJ696FHTseSNJ8EFREZn8XuD0=", - "dev": true - } - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "strip-json-comments": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-3.1.0.tgz?cache=0&sync_timestamp=1594567532500&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-3.1.0.tgz", - "integrity": "sha1-djjTFCISns9EV0QACfugP5+awYA=", - "dev": true - } - } - }, - "eslint-loader": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/eslint-loader/download/eslint-loader-2.2.1.tgz", - "integrity": "sha1-KLnBLaVAV68IReKmEScBova/gzc=", - "dev": true, - "requires": { - "loader-fs-cache": "^1.0.0", - "loader-utils": "^1.0.2", - "object-assign": "^4.0.1", - "object-hash": "^1.1.4", - "rimraf": "^2.6.1" - } - }, - "eslint-plugin-vue": { - "version": "6.2.2", - "resolved": "https://registry.npm.taobao.org/eslint-plugin-vue/download/eslint-plugin-vue-6.2.2.tgz", - "integrity": "sha1-J/7NmjokeJsPER7N1UCp5WGY4P4=", - "dev": true, - "requires": { - "natural-compare": "^1.4.0", - "semver": "^5.6.0", - "vue-eslint-parser": "^7.0.0" - } - }, - "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-5.1.0.tgz", - "integrity": "sha1-0Plx3+WcaeDK2mhLI9Sdv4JgDOU=", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npm.taobao.org/eslint-utils/download/eslint-utils-1.4.3.tgz?cache=0&sync_timestamp=1592222125610&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-utils%2Fdownload%2Feslint-utils-1.4.3.tgz", - "integrity": "sha1-dP7HxU0Hdrb2fgJRBAtYBlZOmB8=", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/eslint-visitor-keys/download/eslint-visitor-keys-1.2.0.tgz?cache=0&sync_timestamp=1592583263569&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-1.2.0.tgz", - "integrity": "sha1-dEFayISHRJX3jsKpc0lSU0TJgfo=", - "dev": true - }, - "espree": { - "version": "6.2.1", - "resolved": "https://registry.npm.taobao.org/espree/download/espree-6.2.1.tgz?cache=0&sync_timestamp=1595034145062&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fespree%2Fdownload%2Fespree-6.2.1.tgz", - "integrity": "sha1-d/xy4f10SiBSwg84pbV1gy6Cc0o=", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz", - "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", - "dev": true - }, - "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/esquery/download/esquery-1.3.1.tgz", - "integrity": "sha1-t4tYKKqOIU4p+3TE1bdS4cAz2lc=", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-5.1.0.tgz?cache=0&sync_timestamp=1586968717941&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-5.1.0.tgz", - "integrity": "sha1-N0MJ05/ZNa5QDnuS6Ka0xyDllkI=", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/esrecurse/download/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-4.3.0.tgz?cache=0&sync_timestamp=1586968717941&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-4.3.0.tgz", - "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0=", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/esutils/download/esutils-2.0.3.tgz", - "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "event-pubsub": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/event-pubsub/download/event-pubsub-4.3.0.tgz", - "integrity": "sha1-9o2Ba8KfHsAsU53FjI3UDOcss24=", - "dev": true - }, - "eventemitter3": { - "version": "4.0.4", - "resolved": "https://registry.npm.taobao.org/eventemitter3/download/eventemitter3-4.0.4.tgz", - "integrity": "sha1-tUY6zmNaCD0Bi9x8kXtMXxCoU4Q=", - "dev": true - }, - "events": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/events/download/events-3.1.0.tgz", - "integrity": "sha1-hCea8bNMt1qoi/X/KR9tC9mzGlk=", - "dev": true - }, - "eventsource": { - "version": "1.0.7", - "resolved": "https://registry.npm.taobao.org/eventsource/download/eventsource-1.0.7.tgz", - "integrity": "sha1-j7xyyT/NNAiAkLwKTmT0tc7m2NA=", - "dev": true, - "requires": { - "original": "^1.0.0" - } - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/evp_bytestokey/download/evp_bytestokey-1.0.3.tgz", - "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", - "dev": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npm.taobao.org/exec-sh/download/exec-sh-0.3.4.tgz", - "integrity": "sha1-OgGM61JsxvbfK7UEsr/o46STTsU=", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/execa/download/execa-1.0.0.tgz?cache=0&sync_timestamp=1594145085955&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexeca%2Fdownload%2Fexeca-1.0.0.tgz", - "integrity": "sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg=", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-6.0.5.tgz?cache=0&sync_timestamp=1590448522710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-spawn%2Fdownload%2Fcross-spawn-6.0.5.tgz", - "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/exit/download/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/expect/download/expect-24.9.0.tgz?cache=0&sync_timestamp=1592926052462&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexpect%2Fdownload%2Fexpect-24.9.0.tgz", - "integrity": "sha1-t1FltIFwdPpKFXeU9G/p8boVtso=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - } - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npm.taobao.org/express/download/express-4.17.1.tgz", - "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", - "dev": true, - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz?cache=0&sync_timestamp=1589129378619&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", - "dev": true - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz", - "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=", - "dev": true - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/external-editor/download/external-editor-3.1.0.tgz", - "integrity": "sha1-ywP3QL764D6k0oPK7SdBqD8zVJU=", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/extglob/download/extglob-2.0.4.tgz", - "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz", - "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", - "dev": true - } - } - }, - "extract-from-css": { - "version": "0.4.4", - "resolved": "https://registry.npm.taobao.org/extract-from-css/download/extract-from-css-0.4.4.tgz", - "integrity": "sha1-HqffLnx8brmSL6COitrqSG9vj5I=", - "dev": true, - "requires": { - "css": "^2.1.0" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz?cache=0&sync_timestamp=1591599604977&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-deep-equal%2Fdownload%2Ffast-deep-equal-3.1.3.tgz", - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", - "dev": true - }, - "fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npm.taobao.org/fast-glob/download/fast-glob-2.2.7.tgz?cache=0&sync_timestamp=1592290326190&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-glob%2Fdownload%2Ffast-glob-2.2.7.tgz", - "integrity": "sha1-aVOFfDr6R1//ku5gFdUtpwpM050=", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz?cache=0&sync_timestamp=1576340291001&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-json-stable-stringify%2Fdownload%2Ffast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/fb-watchman/download/fb-watchman-2.0.1.tgz", - "integrity": "sha1-/IT7OdJwnPP/bXQ3BhV7tXCKioU=", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npm.taobao.org/figgy-pudding/download/figgy-pudding-3.5.2.tgz?cache=0&sync_timestamp=1585068742276&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffiggy-pudding%2Fdownload%2Ffiggy-pudding-3.5.2.tgz", - "integrity": "sha1-tO7oFIq7Adzx0aw0Nn1Z4S+mHW4=", - "dev": true - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/figures/download/figures-3.2.0.tgz", - "integrity": "sha1-YlwYvSk8YE3EqN2y/r8MiDQXRq8=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npm.taobao.org/file-entry-cache/download/file-entry-cache-5.0.1.tgz", - "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "file-loader": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/file-loader/download/file-loader-4.3.0.tgz", - "integrity": "sha1-eA8ED3KbPRgBnyBgX3I+hEuKWK8=", - "dev": true, - "requires": { - "loader-utils": "^1.2.3", - "schema-utils": "^2.5.0" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-1.0.0.tgz", - "integrity": "sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90=", - "dev": true, - "optional": true - }, - "filesize": { - "version": "3.6.1", - "resolved": "https://registry.npm.taobao.org/filesize/download/filesize-3.6.1.tgz?cache=0&sync_timestamp=1582340569604&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffilesize%2Fdownload%2Ffilesize-3.6.1.tgz", - "integrity": "sha1-CQuz7gG2+AGoqL6Z0xcQs0Irsxc=", - "dev": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.2.tgz", - "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - } - }, - "find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/find-babel-config/download/find-babel-config-1.2.0.tgz", - "integrity": "sha1-qbezF+tbmGDNqdVHQKjIM3oig6I=", - "dev": true, - "requires": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-2.1.0.tgz", - "integrity": "sha1-jQ+UzRP+Q8bHwmGg2GEVypGMBfc=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-3.0.0.tgz", - "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/flat-cache/download/flat-cache-2.0.1.tgz", - "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-2.6.3.tgz?cache=0&sync_timestamp=1581229865753&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-2.6.3.tgz", - "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/flatted/download/flatted-2.0.2.tgz", - "integrity": "sha1-RXWyHivO50NKqb5mL0t7X5wrUTg=", - "dev": true - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/flush-write-stream/download/flush-write-stream-1.1.1.tgz", - "integrity": "sha1-jdfYc6G6vCB9lOrQwuDkQnbr8ug=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.5.10.tgz?cache=0&sync_timestamp=1592518349461&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.5.10.tgz", - "integrity": "sha1-e3qfmuov3/NnhqlP9kPtB/T/Xio=", - "requires": { - "debug": "=3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "font-awesome": { - "version": "4.7.0", - "resolved": "https://registry.npm.taobao.org/font-awesome/download/font-awesome-4.7.0.tgz", - "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz", - "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/fragment-cache/download/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npm.taobao.org/fs-extra/download/fs-extra-7.0.1.tgz", - "integrity": "sha1-TxicRKoSO4lfcigE9V6iPq3DSOk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npm.taobao.org/fs-write-stream-atomic/download/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-1.2.13.tgz", - "integrity": "sha1-8yXLBFVZJCi88Rs4M3DvcOO/zDg=", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/functional-red-black-tree/download/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npm.taobao.org/gauge/download/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/aproba/download/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "gaze": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/gaze/download/gaze-1.1.3.tgz", - "integrity": "sha1-xEFzPhO5J6yMD/C0w7Az8ogSkko=", - "dev": true, - "requires": { - "globule": "^1.0.0" - } - }, - "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npm.taobao.org/gensync/download/gensync-1.0.0-beta.1.tgz", - "integrity": "sha1-WPQ2H/mH5f9uHnohCCeqNx6qwmk=", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npm.taobao.org/get-caller-file/download/get-caller-file-2.0.5.tgz", - "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=" - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npm.taobao.org/get-package-type/download/get-package-type-0.1.0.tgz", - "integrity": "sha1-jeLYA8/0TfO8bEVuZmizbDkm4Ro=", - "dev": true - }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/get-stdin/download/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-4.1.0.tgz", - "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/get-value/download/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "github-buttons": { - "version": "2.11.0", - "resolved": "https://registry.npm.taobao.org/github-buttons/download/github-buttons-2.11.0.tgz", - "integrity": "sha1-4FrO9D5nC+CpORKh7GfFQyrMz6c=" - }, - "github-markdown-css": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/github-markdown-css/download/github-markdown-css-4.0.0.tgz", - "integrity": "sha1-vp9Mr3o4kijUw2gzYmD/yQkGHzU=" - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz?cache=0&sync_timestamp=1573078302562&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglob%2Fdownload%2Fglob-7.1.6.tgz", - "integrity": "sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY=", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/glob-to-regexp/download/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npm.taobao.org/globals/download/globals-11.12.0.tgz", - "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", - "dev": true - }, - "globby": { - "version": "9.2.0", - "resolved": "https://registry.npm.taobao.org/globby/download/globby-9.2.0.tgz", - "integrity": "sha1-/QKacGxwPSm90XD0tts6P3p8tj0=", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", - "dev": true - } - } - }, - "globule": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/globule/download/globule-1.3.2.tgz", - "integrity": "sha1-2L3Z6eTu+PluJFmZpd7n612FKcQ=", - "dev": true, - "requires": { - "glob": "~7.1.1", - "lodash": "~4.17.10", - "minimatch": "~3.0.2" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgraceful-fs%2Fdownload%2Fgraceful-fs-4.2.4.tgz", - "integrity": "sha1-Ila94U02MpWMRl68ltxGfKB6Kfs=", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/growly/download/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "gzip-size": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/gzip-size/download/gzip-size-5.1.1.tgz", - "integrity": "sha1-y5vuaS+HwGErIyhAqHOQTkwTUnQ=", - "dev": true, - "requires": { - "duplexer": "^0.1.1", - "pify": "^4.0.1" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", - "dev": true - } - } - }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/handle-thing/download/handle-thing-2.0.1.tgz", - "integrity": "sha1-hX95zjWVgMNA1DCBzGSJcNC7I04=", - "dev": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npm.taobao.org/har-validator/download/har-validator-5.1.3.tgz", - "integrity": "sha1-HvievT5JllV2de7ZiTEQ3DUPoIA=", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz", - "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/has-ansi/download/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.1.tgz", - "integrity": "sha1-n1IUdYpEGWxAbZvXbOv4HsLdMeg=" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/has-unicode/download/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/has-value/download/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/has-values/download/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/hash-base/download/hash-base-3.1.0.tgz", - "integrity": "sha1-VcOB2eBuHSmXqIO0o/3f5/DTrzM=", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "hash-sum": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-2.0.0.tgz", - "integrity": "sha1-gdAbtd6OpKIUrV1urRtSNGCwtFo=", - "dev": true - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npm.taobao.org/hash.js/download/hash.js-1.1.7.tgz", - "integrity": "sha1-C6vKU46NTuSg+JiNaIZlN6ADz0I=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/he/download/he-1.2.0.tgz", - "integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8=", - "dev": true - }, - "hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/hex-color-regex/download/hex-color-regex-1.1.0.tgz", - "integrity": "sha1-TAb8y0YC/iYCs8k9+C1+fb8aio4=", - "dev": true - }, - "highlight.js": { - "version": "9.18.1", - "resolved": "https://registry.npm.taobao.org/highlight.js/download/highlight.js-9.18.1.tgz", - "integrity": "sha1-7SGqAB/mJSuxCj121HVzxlOf4Tw=", - "dev": true - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/hmac-drbg/download/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/hoopy/download/hoopy-0.1.4.tgz", - "integrity": "sha1-YJIH1mEQADOpqUAq096mdzgcGx0=", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npm.taobao.org/hosted-git-info/download/hosted-git-info-2.8.8.tgz?cache=0&sync_timestamp=1594427993800&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhosted-git-info%2Fdownload%2Fhosted-git-info-2.8.8.tgz", - "integrity": "sha1-dTm9S8Hg4KiVgVouAmJCCxKFhIg=", - "dev": true - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npm.taobao.org/hpack.js/download/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/hsl-regex/download/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", - "dev": true - }, - "hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/hsla-regex/download/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", - "dev": true - }, - "html-comment-regex": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/html-comment-regex/download/html-comment-regex-1.1.2.tgz", - "integrity": "sha1-l9RoiutcgYhqNk+qDK0d2hTUM6c=", - "dev": true - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/html-encoding-sniffer/download/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha1-5w2EuU2lOqN14R/jo1G+ZkLKRvg=", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "html-entities": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/html-entities/download/html-entities-1.3.1.tgz", - "integrity": "sha1-+5oaS1sUxdq6gtPjTGrk/nAaDkQ=", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/html-escaper/download/html-escaper-2.0.2.tgz?cache=0&sync_timestamp=1585317058766&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhtml-escaper%2Fdownload%2Fhtml-escaper-2.0.2.tgz", - "integrity": "sha1-39YAJ9o2o238viNiYsAKWCJoFFM=", - "dev": true - }, - "html-minifier": { - "version": "3.5.21", - "resolved": "https://registry.npm.taobao.org/html-minifier/download/html-minifier-3.5.21.tgz", - "integrity": "sha1-0AQOBUcw41TbAIRjWTGUAVIS0gw=", - "dev": true, - "requires": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" - }, - "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.17.1.tgz?cache=0&sync_timestamp=1592632050401&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.17.1.tgz", - "integrity": "sha1-vXerfebelCBc6sxy8XFtKfIKd78=", - "dev": true - } - } - }, - "html-tags": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/html-tags/download/html-tags-2.0.0.tgz", - "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", - "dev": true - }, - "html-webpack-plugin": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz", - "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", - "dev": true, - "requires": { - "html-minifier": "^3.2.3", - "loader-utils": "^0.2.16", - "lodash": "^4.17.3", - "pretty-error": "^2.0.2", - "tapable": "^1.0.0", - "toposort": "^1.0.0", - "util.promisify": "1.0.0" - }, - "dependencies": { - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/big.js/download/big.js-3.2.0.tgz", - "integrity": "sha1-pfwpi4G54Nyi5FiCR4S2XFK6WI4=", - "dev": true - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "dev": true, - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" - } - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.0.tgz", - "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - } - } - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npm.taobao.org/htmlparser2/download/htmlparser2-3.10.1.tgz", - "integrity": "sha1-vWedw/WYl7ajS7EHSchVu1OpOS8=", - "dev": true, - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npm.taobao.org/http-deceiver/download/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.2.tgz?cache=0&sync_timestamp=1593407647372&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.2.tgz", - "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } - } - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npm.taobao.org/http-proxy/download/http-proxy-1.18.1.tgz", - "integrity": "sha1-QBVB8FNIhLv5UmAzTnL4juOXZUk=", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://registry.npm.taobao.org/http-proxy-middleware/download/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha1-GDx9xKoUeRUDBkmMIQza+WCApDo=", - "dev": true, - "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz?cache=0&sync_timestamp=1585807780313&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-signature%2Fdownload%2Fhttp-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/https-browserify/download/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/human-signals/download/human-signals-1.1.1.tgz", - "integrity": "sha1-xbHNFPUK6uCatsWf5jujOV/k36M=", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz?cache=0&sync_timestamp=1594184264130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.24.tgz", - "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-utils": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/icss-utils/download/icss-utils-4.1.1.tgz", - "integrity": "sha1-IRcLU3ie4nRHwvR91oMIFAP5pGc=", - "dev": true, - "requires": { - "postcss": "^7.0.14" - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npm.taobao.org/ieee754/download/ieee754-1.1.13.tgz", - "integrity": "sha1-7BaFWOlaoYH9h9N/VcMrvLZwi4Q=", - "dev": true - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npm.taobao.org/iferr/download/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npm.taobao.org/ignore/download/ignore-4.0.6.tgz", - "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", - "dev": true - }, - "import-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/import-cwd/download/import-cwd-2.1.0.tgz", - "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", - "dev": true, - "requires": { - "import-from": "^2.1.0" - } - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npm.taobao.org/import-fresh/download/import-fresh-3.2.1.tgz", - "integrity": "sha1-Yz/2GFBueTr1rJG/SLcmd+FcvmY=", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/resolve-from/download/resolve-from-4.0.0.tgz", - "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", - "dev": true - } - } - }, - "import-from": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/import-from/download/import-from-2.1.0.tgz", - "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/import-local/download/import-local-2.0.0.tgz", - "integrity": "sha1-VQcL44pZk88Y72236WH1vuXFoJ0=", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "in-publish": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/in-publish/download/in-publish-2.0.1.tgz", - "integrity": "sha1-lIsaU1yAMFYc6lIvc/ePS+NX4Aw=", - "dev": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/indent-string/download/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/indexes-of/download/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/infer-owner/download/infer-owner-1.0.4.tgz", - "integrity": "sha1-xM78qo5RBRwqQLos6KPScpWvlGc=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz", - "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npm.taobao.org/ini/download/ini-1.3.5.tgz", - "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", - "dev": true - }, - "inquirer": { - "version": "7.2.0", - "resolved": "https://registry.npm.taobao.org/inquirer/download/inquirer-7.2.0.tgz?cache=0&sync_timestamp=1594660440251&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Finquirer%2Fdownload%2Finquirer-7.2.0.tgz", - "integrity": "sha1-Y86Z2CMJDefrQg5LsF5vNEmqOJo=", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^3.0.0", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.5.3", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npm.taobao.org/ansi-escapes/download/ansi-escapes-4.3.1.tgz?cache=0&sync_timestamp=1583072820951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-escapes%2Fdownload%2Fansi-escapes-4.3.1.tgz", - "integrity": "sha1-pcR8xDGB8fOP/XB2g3cA05VSKmE=", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-5.0.0.tgz", - "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.2.1.tgz", - "integrity": "sha1-kK51xCTQCNJiTFvynq0xd+v881k=", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-3.0.0.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-3.0.0.tgz", - "integrity": "sha1-P3PCv1JlkfV0zEksUeJFY0n4ROQ=", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-8.0.0.tgz", - "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-4.2.0.tgz", - "integrity": "sha1-lSGCxGzHssMT0VluYjmSvRY7crU=", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-6.0.0.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-6.0.0.tgz", - "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.1.0.tgz?cache=0&sync_timestamp=1569557271992&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.1.0.tgz", - "integrity": "sha1-aOMlkd9z4lrRxLSRCKLsUHliv9E=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npm.taobao.org/type-fest/download/type-fest-0.11.0.tgz?cache=0&sync_timestamp=1593290909259&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftype-fest%2Fdownload%2Ftype-fest-0.11.0.tgz", - "integrity": "sha1-l6vwhyMQ/tiKXEZrJWgVdhReM/E=", - "dev": true - } - } - }, - "internal-ip": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/internal-ip/download/internal-ip-4.3.0.tgz?cache=0&sync_timestamp=1583983307284&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Finternal-ip%2Fdownload%2Finternal-ip-4.3.0.tgz", - "integrity": "sha1-hFRSuq2dLKO2nGNaE3rLmg2tCQc=", - "dev": true, - "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - }, - "dependencies": { - "default-gateway": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/default-gateway/download/default-gateway-4.2.0.tgz", - "integrity": "sha1-FnEEx1AMIRX23WmwpTa7jtcgVSs=", - "dev": true, - "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" - } - } - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npm.taobao.org/invariant/download/invariant-2.2.4.tgz", - "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npm.taobao.org/ip/download/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/ip-regex/download/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.9.1.tgz", - "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=", - "dev": true - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-absolute-url/download/is-absolute-url-2.1.0.tgz?cache=0&sync_timestamp=1569735515256&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-absolute-url%2Fdownload%2Fis-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/is-arguments/download/is-arguments-1.0.4.tgz", - "integrity": "sha1-P6+WbHy6D/Q3+zH2JQCC/PBEjPM=" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/is-callable/download/is-callable-1.2.0.tgz", - "integrity": "sha1-gzNlYLVKOONeOi33r9BFTWkUaLs=" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-ci/download/is-ci-2.0.0.tgz", - "integrity": "sha1-a8YzQYGBDgS1wis9WJ/cpVAmQEw=", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-color-stop/download/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dev": true, - "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-date-object/download/is-date-object-1.0.2.tgz?cache=0&sync_timestamp=1576729165697&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-date-object%2Fdownload%2Fis-date-object-1.0.2.tgz", - "integrity": "sha1-vac28s2P0G0yhE53Q7+nSUw7/X4=" - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", - "dev": true - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npm.taobao.org/is-directory/download/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-docker": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-docker/download/is-docker-2.0.0.tgz", - "integrity": "sha1-LLDfDnXi0GT+GGTDfN6st7Lc8ls=", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-finite/download/is-finite-1.1.0.tgz?cache=0&sync_timestamp=1581061033879&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-finite%2Fdownload%2Fis-finite-1.1.0.tgz", - "integrity": "sha1-kEE1x3+0LAZB1qobzbxNqo2ggvM=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-generator-fn/download/is-generator-fn-2.1.0.tgz", - "integrity": "sha1-fRQK3DiarzARqPKipM+m+q3/sRg=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz", - "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/is-path-cwd/download/is-path-cwd-2.2.0.tgz", - "integrity": "sha1-Z9Q7gmZKe1GR/ZEZEn6zAASKn9s=", - "dev": true - }, - "is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-path-in-cwd/download/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha1-v+Lcomxp85cmWkAJljYCk1oFOss=", - "dev": true, - "requires": { - "is-path-inside": "^2.1.0" - }, - "dependencies": { - "is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-path-inside/download/is-path-inside-2.1.0.tgz", - "integrity": "sha1-fJgQWH1lmkDSe8201WFuqwWUlLI=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.2" - } - } - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-plain-obj/download/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/is-plain-object/download/is-plain-object-2.0.4.tgz?cache=0&sync_timestamp=1593243637677&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-plain-object%2Fdownload%2Fis-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-regex/download/is-regex-1.1.0.tgz", - "integrity": "sha1-7OOOOJ5JDfDcIcrqK9WW+Yf3Z/8=", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-resolvable/download/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-stream/download/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-svg": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/is-svg/download/is-svg-3.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-svg%2Fdownload%2Fis-svg-3.0.0.tgz", - "integrity": "sha1-kyHb0pwhLlypnE+peUxxS8r6L3U=", - "dev": true, - "requires": { - "html-comment-regex": "^1.1.0" - } - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/is-symbol/download/is-symbol-1.0.3.tgz?cache=0&sync_timestamp=1574296721350&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-symbol%2Fdownload%2Fis-symbol-1.0.3.tgz", - "integrity": "sha1-OOEBS55jKb4N6dJKQU/XRB7GGTc=", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/is-utf8/download/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-whitespace": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/is-whitespace/download/is-whitespace-0.3.0.tgz", - "integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-windows/download/is-windows-1.0.2.tgz", - "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/is-wsl/download/is-wsl-1.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-wsl%2Fdownload%2Fis-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/isobject/download/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npm.taobao.org/istanbul-lib-coverage/download/istanbul-lib-coverage-2.0.5.tgz?cache=0&sync_timestamp=1577062542104&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fistanbul-lib-coverage%2Fdownload%2Fistanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha1-Z18KtpUD+tSx2En3NrqsqAM0T0k=", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npm.taobao.org/istanbul-lib-instrument/download/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha1-pfY9kfC7wMPkee9MXeAnM17G1jA=", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npm.taobao.org/istanbul-lib-report/download/istanbul-lib-report-2.0.8.tgz?cache=0&sync_timestamp=1577062542584&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fistanbul-lib-report%2Fdownload%2Fistanbul-lib-report-2.0.8.tgz", - "integrity": "sha1-WoETzXRtQ8SInro2qxDn1QybTzM=", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npm.taobao.org/istanbul-lib-source-maps/download/istanbul-lib-source-maps-3.0.6.tgz?cache=0&sync_timestamp=1577062542893&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fistanbul-lib-source-maps%2Fdownload%2Fistanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha1-KEmXxIIRdS7EhiU9qX44ed77qMg=", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "istanbul-reports": { - "version": "2.2.7", - "resolved": "https://registry.npm.taobao.org/istanbul-reports/download/istanbul-reports-2.2.7.tgz", - "integrity": "sha1-XZOfYjfXtIOTzAlZ6rQM1P0FaTE=", - "dev": true, - "requires": { - "html-escaper": "^2.0.0" - } - }, - "javascript-stringify": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/javascript-stringify/download/javascript-stringify-2.0.1.tgz?cache=0&sync_timestamp=1572948916758&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjavascript-stringify%2Fdownload%2Fjavascript-stringify-2.0.1.tgz", - "integrity": "sha1-bvNYA1MQ411mfGde1j0+t8GqGeU=", - "dev": true - }, - "jest": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest/download/jest-24.9.0.tgz?cache=0&sync_timestamp=1592925455019&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest%2Fdownload%2Fjest-24.9.0.tgz", - "integrity": "sha1-mH0pDAWgi1LFYYjBAC42jtsAcXE=", - "dev": true, - "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.9.0" - }, - "dependencies": { - "jest-cli": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-cli/download/jest-cli-24.9.0.tgz?cache=0&sync_timestamp=1592926450218&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-cli%2Fdownload%2Fjest-cli-24.9.0.tgz", - "integrity": "sha1-rS3mLQdHLUGcarwwH8QyuYsQ0q8=", - "dev": true, - "requires": { - "@jest/core": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "import-local": "^2.0.0", - "is-ci": "^2.0.0", - "jest-config": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "prompts": "^2.0.1", - "realpath-native": "^1.1.0", - "yargs": "^13.3.0" - } - } - } - }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-changed-files/download/jest-changed-files-24.9.0.tgz?cache=0&sync_timestamp=1592925334512&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-changed-files%2Fdownload%2Fjest-changed-files-24.9.0.tgz", - "integrity": "sha1-CNjBXreaf6P8mCabwUtFHugvgDk=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" - } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-config/download/jest-config-24.9.0.tgz", - "integrity": "sha1-+xu8YMc6Rq8DWQcZ76SCXm5N0bU=", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" - }, - "dependencies": { - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/babel-jest/download/babel-jest-24.9.0.tgz?cache=0&sync_timestamp=1592926057142&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-jest%2Fdownload%2Fbabel-jest-24.9.0.tgz", - "integrity": "sha1-P8Mny4RnuJ0U17xw4xUQSng8zVQ=", - "dev": true, - "requires": { - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.9.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/babel-plugin-jest-hoist/download/babel-plugin-jest-hoist-24.9.0.tgz?cache=0&sync_timestamp=1592926445554&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-plugin-jest-hoist%2Fdownload%2Fbabel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha1-T4NwketAfgFEfIhDy+xUbQAC11Y=", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/babel-preset-jest/download/babel-preset-jest-24.9.0.tgz?cache=0&sync_timestamp=1592927135667&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-preset-jest%2Fdownload%2Fbabel-preset-jest-24.9.0.tgz", - "integrity": "sha1-GStSHiIX+x0fZ89z9wwzZlCtPNw=", - "dev": true, - "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" - } - } - } - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-diff/download/jest-diff-24.9.0.tgz?cache=0&sync_timestamp=1592926531670&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-diff%2Fdownload%2Fjest-diff-24.9.0.tgz", - "integrity": "sha1-kxt9DVd4obr3RSy4FuMl43JAVdo=", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-docblock": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-docblock/download/jest-docblock-24.9.0.tgz", - "integrity": "sha1-eXAgGAK6Vg4cQJLMJcvt9a9ajOI=", - "dev": true, - "requires": { - "detect-newline": "^2.1.0" - } - }, - "jest-each": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-each/download/jest-each-24.9.0.tgz?cache=0&sync_timestamp=1592926443134&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-each%2Fdownload%2Fjest-each-24.9.0.tgz", - "integrity": "sha1-6y2mAuKmEImNvF8fbfO6hrVfiwU=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-environment-jsdom": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-environment-jsdom/download/jest-environment-jsdom-24.9.0.tgz?cache=0&sync_timestamp=1592926446068&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-environment-jsdom%2Fdownload%2Fjest-environment-jsdom-24.9.0.tgz", - "integrity": "sha1-SwgGx/yU+V7bNpppzCd47sK3N1s=", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0", - "jsdom": "^11.5.1" - } - }, - "jest-environment-jsdom-fifteen": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/jest-environment-jsdom-fifteen/download/jest-environment-jsdom-fifteen-1.0.2.tgz", - "integrity": "sha1-SaCvVeDTJzemEUoVdd1xRwKtY7A=", - "dev": true, - "requires": { - "@jest/environment": "^24.3.0", - "@jest/fake-timers": "^24.3.0", - "@jest/types": "^24.3.0", - "jest-mock": "^24.0.0", - "jest-util": "^24.0.0", - "jsdom": "^15.2.1" - }, - "dependencies": { - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npm.taobao.org/cssom/download/cssom-0.4.4.tgz", - "integrity": "sha1-WmbPk9LQtmHYC/akT7ZfXC5OChA=", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/cssstyle/download/cssstyle-2.3.0.tgz?cache=0&sync_timestamp=1588172192426&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcssstyle%2Fdownload%2Fcssstyle-2.3.0.tgz", - "integrity": "sha1-/2ZaDdvcMYZLCWR/NBY0Q9kLCFI=", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npm.taobao.org/cssom/download/cssom-0.3.8.tgz", - "integrity": "sha1-nxJ29bK0Y/IRTT8sdSUK+MGjb0o=", - "dev": true - } - } - }, - "jsdom": { - "version": "15.2.1", - "resolved": "https://registry.npm.taobao.org/jsdom/download/jsdom-15.2.1.tgz", - "integrity": "sha1-0v6xrvcYP4a+UhuMaDP/UpbQfsU=", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^7.1.0", - "acorn-globals": "^4.3.2", - "array-equal": "^1.0.0", - "cssom": "^0.4.1", - "cssstyle": "^2.0.0", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.1", - "html-encoding-sniffer": "^1.0.2", - "nwsapi": "^2.2.0", - "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.7", - "saxes": "^3.1.9", - "symbol-tree": "^3.2.2", - "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.1.2", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^7.0.0", - "xml-name-validator": "^3.0.0" - } - }, - "parse5": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/parse5/download/parse5-5.1.0.tgz", - "integrity": "sha1-xZNByXI/QUxFKXVWTHwApo1YrNI=", - "dev": true - }, - "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/tough-cookie/download/tough-cookie-3.0.1.tgz", - "integrity": "sha1-nfT1fnOcJpMKAYGEiH9K233Kc7I=", - "dev": true, - "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/whatwg-url/download/whatwg-url-7.1.0.tgz", - "integrity": "sha1-wsSS8eymEpiO/T0iZr4bn8YXDQY=", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "ws": { - "version": "7.3.1", - "resolved": "https://registry.npm.taobao.org/ws/download/ws-7.3.1.tgz?cache=0&sync_timestamp=1593925423349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fws%2Fdownload%2Fws-7.3.1.tgz", - "integrity": "sha1-0FR79n985PEqct/jEmLGjX3FUcg=", - "dev": true - } - } - }, - "jest-environment-node": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-environment-node/download/jest-environment-node-24.9.0.tgz?cache=0&sync_timestamp=1592926446359&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-environment-node%2Fdownload%2Fjest-environment-node-24.9.0.tgz", - "integrity": "sha1-Mz0tJ5b5aH8q7r8HQrUZ8zwcv9M=", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0" - } - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-get-type/download/jest-get-type-24.9.0.tgz", - "integrity": "sha1-FoSgyKUPLkkBtmRK6GH1ee7S7w4=", - "dev": true - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-haste-map/download/jest-haste-map-24.9.0.tgz?cache=0&sync_timestamp=1592925338595&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-haste-map%2Fdownload%2Fjest-haste-map-24.9.0.tgz", - "integrity": "sha1-s4pdZCdJNOIfpBeump++t3zqrH0=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-jasmine2/download/jest-jasmine2-24.9.0.tgz", - "integrity": "sha1-H3sb0yQsF3TmKsq7NkbZavw75qA=", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^24.9.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0", - "throat": "^4.0.0" - } - }, - "jest-leak-detector": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-leak-detector/download/jest-leak-detector-24.9.0.tgz?cache=0&sync_timestamp=1592925342819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-leak-detector%2Fdownload%2Fjest-leak-detector-24.9.0.tgz", - "integrity": "sha1-tmXep8dxAMXE99/LFTtlzwfc+Wo=", - "dev": true, - "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-matcher-utils/download/jest-matcher-utils-24.9.0.tgz?cache=0&sync_timestamp=1592926050890&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-matcher-utils%2Fdownload%2Fjest-matcher-utils-24.9.0.tgz", - "integrity": "sha1-9bNmHV5ijf/m3WUlHf2uDofDoHM=", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-message-util/download/jest-message-util-24.9.0.tgz", - "integrity": "sha1-Un9UoeOA9eICqNEUmw7IcvQxGeM=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-mock/download/jest-mock-24.9.0.tgz?cache=0&sync_timestamp=1592927133688&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-mock%2Fdownload%2Fjest-mock-24.9.0.tgz", - "integrity": "sha1-wig1VB7jebkIZzrVEIeiGFwT8cY=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npm.taobao.org/jest-pnp-resolver/download/jest-pnp-resolver-1.2.2.tgz?cache=0&sync_timestamp=1592991682490&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-pnp-resolver%2Fdownload%2Fjest-pnp-resolver-1.2.2.tgz", - "integrity": "sha1-twSsCuAoqJEIpNBAs/kZ393I4zw=", - "dev": true - }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-regex-util/download/jest-regex-util-24.9.0.tgz", - "integrity": "sha1-wT+zOAveIr9ldUMsST6o/jeWVjY=", - "dev": true - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-resolve/download/jest-resolve-24.9.0.tgz?cache=0&sync_timestamp=1592925341455&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-resolve%2Fdownload%2Fjest-resolve-24.9.0.tgz", - "integrity": "sha1-3/BMdoevNMTdflJIktnPd+XRcyE=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-resolve-dependencies": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-resolve-dependencies/download/jest-resolve-dependencies-24.9.0.tgz?cache=0&sync_timestamp=1592926061421&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-resolve-dependencies%2Fdownload%2Fjest-resolve-dependencies-24.9.0.tgz", - "integrity": "sha1-rQVRmJWcTPuopPBmxnOj8HhlB6s=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.0" - } - }, - "jest-runner": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-runner/download/jest-runner-24.9.0.tgz?cache=0&sync_timestamp=1592926063005&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-runner%2Fdownload%2Fjest-runner-24.9.0.tgz", - "integrity": "sha1-V0+v29VEVcKzS0vfQ2WiOFf830I=", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.4.2", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-docblock": "^24.3.0", - "jest-haste-map": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-leak-detector": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" - } - }, - "jest-runtime": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-runtime/download/jest-runtime-24.9.0.tgz?cache=0&sync_timestamp=1592926065810&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-runtime%2Fdownload%2Fjest-runtime-24.9.0.tgz", - "integrity": "sha1-nxRYOvak9zFKap2fAibhp4HI5Kw=", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/source-map": "^24.3.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "strip-bom": "^3.0.0", - "yargs": "^13.3.0" - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-serializer/download/jest-serializer-24.9.0.tgz?cache=0&sync_timestamp=1592926443254&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-serializer%2Fdownload%2Fjest-serializer-24.9.0.tgz", - "integrity": "sha1-5tfX75bTHouQeacUdUxdXFgojnM=", - "dev": true - }, - "jest-serializer-vue": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/jest-serializer-vue/download/jest-serializer-vue-2.0.2.tgz", - "integrity": "sha1-sjjvKGNX7GtIBCG9RxRQUJh9WbM=", - "dev": true, - "requires": { - "pretty": "2.0.0" - } - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-snapshot/download/jest-snapshot-24.9.0.tgz?cache=0&sync_timestamp=1592926059936&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-snapshot%2Fdownload%2Fjest-snapshot-24.9.0.tgz", - "integrity": "sha1-7I6cpPLsDFyHro+SXPl0l7DpUbo=", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "jest-transform-stub": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/jest-transform-stub/download/jest-transform-stub-2.0.0.tgz", - "integrity": "sha1-GQGLCFH3VolyFHpdYAdLVfAiWn0=", - "dev": true - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-util/download/jest-util-24.9.0.tgz?cache=0&sync_timestamp=1592925342680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-util%2Fdownload%2Fjest-util-24.9.0.tgz", - "integrity": "sha1-c5aBTkhTbS6Fo33j5MQx18sUAWI=", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - } - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-validate/download/jest-validate-24.9.0.tgz?cache=0&sync_timestamp=1592925336825&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-validate%2Fdownload%2Fjest-validate-24.9.0.tgz", - "integrity": "sha1-B3XFU2DRc82FTkAYB1bU/1Le+Ks=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } - }, - "jest-watch-typeahead": { - "version": "0.4.2", - "resolved": "https://registry.npm.taobao.org/jest-watch-typeahead/download/jest-watch-typeahead-0.4.2.tgz", - "integrity": "sha1-5b6Vlpin+iMCIppQgsSIw8h4Cko=", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^2.4.1", - "jest-regex-util": "^24.9.0", - "jest-watcher": "^24.3.0", - "slash": "^3.0.0", - "string-length": "^3.1.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npm.taobao.org/ansi-escapes/download/ansi-escapes-4.3.1.tgz?cache=0&sync_timestamp=1583072820951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-escapes%2Fdownload%2Fansi-escapes-4.3.1.tgz", - "integrity": "sha1-pcR8xDGB8fOP/XB2g3cA05VSKmE=", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/slash/download/slash-3.0.0.tgz", - "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", - "dev": true - }, - "string-length": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/string-length/download/string-length-3.1.0.tgz", - "integrity": "sha1-EH74wjRW4Yeoq9SmEWL/SsbiWDc=", - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^5.2.0" - } - }, - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npm.taobao.org/type-fest/download/type-fest-0.11.0.tgz?cache=0&sync_timestamp=1593290909259&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftype-fest%2Fdownload%2Ftype-fest-0.11.0.tgz", - "integrity": "sha1-l6vwhyMQ/tiKXEZrJWgVdhReM/E=", - "dev": true - } - } - }, - "jest-watcher": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-watcher/download/jest-watcher-24.9.0.tgz", - "integrity": "sha1-S1bl0c7/AF9biOUo3Jr8jdTtKzs=", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "jest-util": "^24.9.0", - "string-length": "^2.0.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/jest-worker/download/jest-worker-24.9.0.tgz", - "integrity": "sha1-Xb/bWy0yLphWeJgjipaXvM5ns+U=", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - } - }, - "js-base64": { - "version": "2.6.3", - "resolved": "https://registry.npm.taobao.org/js-base64/download/js-base64-2.6.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-base64%2Fdownload%2Fjs-base64-2.6.3.tgz", - "integrity": "sha1-ev25tXqncX4V03C2bo82qcuDXcM=", - "dev": true - }, - "js-beautify": { - "version": "1.11.0", - "resolved": "https://registry.npm.taobao.org/js-beautify/download/js-beautify-1.11.0.tgz", - "integrity": "sha1-r7hz3EfViYY2AJPctplR6LzV3tI=", - "dev": true, - "requires": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "mkdirp": "~1.0.3", - "nopt": "^4.0.3" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-1.0.4.tgz?cache=0&sync_timestamp=1587535418745&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmkdirp%2Fdownload%2Fmkdirp-1.0.4.tgz", - "integrity": "sha1-PrXtYmInVteaXw4qIh3+utdcL34=", - "dev": true - } - } - }, - "js-cookie": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/js-cookie/download/js-cookie-2.2.1.tgz", - "integrity": "sha1-aeEG3F1YBolFYpAqpbrsN0Tpsrg=" - }, - "js-message": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/js-message/download/js-message-1.0.5.tgz", - "integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=", - "dev": true - }, - "js-queue": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/js-queue/download/js-queue-2.0.0.tgz", - "integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", - "dev": true, - "requires": { - "easy-stack": "^1.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/js-tokens/download/js-tokens-4.0.0.tgz", - "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", - "dev": true - }, - "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npm.taobao.org/js-yaml/download/js-yaml-3.14.0.tgz", - "integrity": "sha1-p6NBcPJqIbsWJCTYray0ETpp5II=", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/jsbn/download/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npm.taobao.org/jsdom/download/jsdom-11.12.0.tgz", - "integrity": "sha1-GoDUDd03ih3lllbp5txaO6hle8g=", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-5.7.4.tgz?cache=0&sync_timestamp=1591869461226&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-5.7.4.tgz", - "integrity": "sha1-Po2KmUfQWZoXltECJddDL0pKz14=", - "dev": true - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/parse5/download/parse5-4.0.0.tgz", - "integrity": "sha1-bXhlbj2o14tOwLkG98CO8d/j9gg=", - "dev": true - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npm.taobao.org/ws/download/ws-5.2.2.tgz?cache=0&sync_timestamp=1593925423349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fws%2Fdownload%2Fws-5.2.2.tgz", - "integrity": "sha1-3/7xSGa46NyRM1glFNG++vlumA8=", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npm.taobao.org/jsesc/download/jsesc-2.5.2.tgz", - "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/json-parse-better-errors/download/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json3": { - "version": "3.3.3", - "resolved": "https://registry.npm.taobao.org/json3/download/json3-3.3.3.tgz", - "integrity": "sha1-f8EON1/FrkLEcFpcwKpvYr4wW4E=", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npm.taobao.org/json5/download/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "jump.js": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/jump.js/download/jump.js-1.0.2.tgz", - "integrity": "sha1-4GQbR/QKOPITnCX9oFAL8o5DAVo=" - }, - "killable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/killable/download/killable-1.0.1.tgz", - "integrity": "sha1-TIzkQRh6Bhx0dPuHygjipjgZSJI=", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/kleur/download/kleur-3.0.3.tgz?cache=0&sync_timestamp=1593042108894&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkleur%2Fdownload%2Fkleur-3.0.3.tgz", - "integrity": "sha1-p5yezIbuHOP6YgbRIWxQHxR/wH4=", - "dev": true - }, - "launch-editor": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/launch-editor/download/launch-editor-2.2.1.tgz", - "integrity": "sha1-hxtaPuOdZoD8wm03kwtu7aidsMo=", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "shell-quote": "^1.6.1" - } - }, - "launch-editor-middleware": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/launch-editor-middleware/download/launch-editor-middleware-2.2.1.tgz", - "integrity": "sha1-4UsH5scVSwpLhqD9NFeE5FgEwVc=", - "dev": true, - "requires": { - "launch-editor": "^2.2.1" - } - }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/left-pad/download/left-pad-1.3.0.tgz", - "integrity": "sha1-W4o6d2Xf4AEmHd6RVYnngvjJTR4=", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/leven/download/leven-3.1.0.tgz", - "integrity": "sha1-d4kd6DQGTMy6gq54QrtrFKE+1/I=", - "dev": true - }, - "levenary": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/levenary/download/levenary-1.1.1.tgz", - "integrity": "sha1-hCqe6Y0gdap/ru2+MmeekgX0b3c=", - "dev": true, - "requires": { - "leven": "^3.1.0" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/levn/download/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npm.taobao.org/lines-and-columns/download/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/load-json-file/download/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "dependencies": { - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/parse-json/download/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/strip-bom/download/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - } - } - }, - "loader-fs-cache": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/loader-fs-cache/download/loader-fs-cache-1.0.3.tgz", - "integrity": "sha1-8IZXZG1gcHi+LwoDL4vWndbyd9k=", - "dev": true, - "requires": { - "find-cache-dir": "^0.1.1", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-0.1.1.tgz", - "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dev": true, - "requires": { - "find-up": "^1.0.0" - } - } - } - }, - "loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npm.taobao.org/loader-runner/download/loader-runner-2.4.0.tgz?cache=0&sync_timestamp=1593786221739&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Floader-runner%2Fdownload%2Floader-runner-2.4.0.tgz", - "integrity": "sha1-7UcGa/5TTX6ExMe5mYwqdWB9k1c=", - "dev": true - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-1.4.0.tgz", - "integrity": "sha1-xXm140yzSxp07cbB+za/o3HVphM=", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/json5/download/json5-1.0.1.tgz", - "integrity": "sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4=", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-3.0.0.tgz", - "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.15.tgz?cache=0&sync_timestamp=1594226958603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.15.tgz", - "integrity": "sha1-tEf2ZwoEVbv+7dETku/zMOoJdUg=", - "dev": true - }, - "lodash.defaultsdeep": { - "version": "4.6.1", - "resolved": "https://registry.npm.taobao.org/lodash.defaultsdeep/download/lodash.defaultsdeep-4.6.1.tgz", - "integrity": "sha1-US6b1yHSctlOPTpjZT+hdRZ0HKY=", - "dev": true - }, - "lodash.kebabcase": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/lodash.kebabcase/download/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", - "dev": true - }, - "lodash.mapvalues": { - "version": "4.6.0", - "resolved": "https://registry.npm.taobao.org/lodash.mapvalues/download/lodash.mapvalues-4.6.0.tgz", - "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npm.taobao.org/lodash.memoize/download/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npm.taobao.org/lodash.sortby/download/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "lodash.transform": { - "version": "4.6.0", - "resolved": "https://registry.npm.taobao.org/lodash.transform/download/lodash.transform-4.6.0.tgz", - "integrity": "sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A=", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npm.taobao.org/lodash.uniq/download/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/log-symbols/download/log-symbols-2.2.0.tgz?cache=0&sync_timestamp=1587898945730&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flog-symbols%2Fdownload%2Flog-symbols-2.2.0.tgz", - "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "loglevel": { - "version": "1.6.8", - "resolved": "https://registry.npm.taobao.org/loglevel/download/loglevel-1.6.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Floglevel%2Fdownload%2Floglevel-1.6.8.tgz", - "integrity": "sha1-iiX7ddCSIw7NRFcnDYC1TigBEXE=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz", - "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npm.taobao.org/loud-rejection/download/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - } - }, - "lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/lower-case/download/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", - "dev": true - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-5.1.1.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-5.1.1.tgz", - "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-2.1.0.tgz?cache=0&sync_timestamp=1587567693680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmake-dir%2Fdownload%2Fmake-dir-2.1.0.tgz", - "integrity": "sha1-XwMQ4YuL6JjMBwCSlaMK5B6R5vU=", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npm.taobao.org/make-error/download/make-error-1.3.6.tgz?cache=0&sync_timestamp=1582105487630&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmake-error%2Fdownload%2Fmake-error-1.3.6.tgz", - "integrity": "sha1-LrLjfqm2fEiR9oShOUeZr0hM96I=", - "dev": true - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npm.taobao.org/makeerror/download/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npm.taobao.org/map-cache/download/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/map-obj/download/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/map-visit/download/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz", - "integrity": "sha1-tdB7jjIW4+J81yjXL3DR5qNCAF8=", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/mdn-data/download/mdn-data-2.0.4.tgz?cache=0&sync_timestamp=1593510420945&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmdn-data%2Fdownload%2Fmdn-data-2.0.4.tgz", - "integrity": "sha1-aZs8OKxvHXKAkaZGULZdOIUC/Vs=", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npm.taobao.org/memory-fs/download/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npm.taobao.org/meow/download/meow-3.7.0.tgz?cache=0&sync_timestamp=1589206039620&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmeow%2Fdownload%2Fmeow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/merge-source-map/download/merge-source-map-1.1.0.tgz", - "integrity": "sha1-L93n5gIJOfcJBqaPLXrmheTIxkY=", - "dev": true, - "requires": { - "source-map": "^0.6.1" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/merge-stream/download/merge-stream-2.0.0.tgz", - "integrity": "sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A=", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/merge2/download/merge2-1.4.1.tgz?cache=0&sync_timestamp=1591169980723&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmerge2%2Fdownload%2Fmerge2-1.4.1.tgz", - "integrity": "sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4=", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npm.taobao.org/micromatch/download/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz", - "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", - "dev": true - } - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/miller-rabin/download/miller-rabin-4.0.1.tgz", - "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "mime": { - "version": "2.4.6", - "resolved": "https://registry.npm.taobao.org/mime/download/mime-2.4.6.tgz?cache=0&sync_timestamp=1590596706367&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime%2Fdownload%2Fmime-2.4.6.tgz", - "integrity": "sha1-5bQHyQ20QvK+tbFiNz0Htpr/pNE=", - "dev": true - }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npm.taobao.org/mime-db/download/mime-db-1.44.0.tgz", - "integrity": "sha1-+hHF6wrKEzS0Izy01S8QxaYnL5I=", - "dev": true - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.27.tgz", - "integrity": "sha1-R5SfmOJ56lMRn1ci4PNOUpvsAJ8=", - "dev": true, - "requires": { - "mime-db": "1.44.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", - "dev": true - }, - "mini-css-extract-plugin": { - "version": "0.9.0", - "resolved": "https://registry.npm.taobao.org/mini-css-extract-plugin/download/mini-css-extract-plugin-0.9.0.tgz?cache=0&sync_timestamp=1576856499989&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmini-css-extract-plugin%2Fdownload%2Fmini-css-extract-plugin-0.9.0.tgz", - "integrity": "sha1-R/LPB6oWWrNXM7H8l9TEbAVkM54=", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "normalize-url": "1.9.1", - "schema-utils": "^1.0.0", - "webpack-sources": "^1.1.0" - }, - "dependencies": { - "normalize-url": { - "version": "1.9.1", - "resolved": "https://registry.npm.taobao.org/normalize-url/download/normalize-url-1.9.1.tgz", - "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "prepend-http": "^1.0.0", - "query-string": "^4.1.0", - "sort-keys": "^1.0.0" - } - }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npm.taobao.org/query-string/download/query-string-4.3.4.tgz?cache=0&sync_timestamp=1591853393825&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fquery-string%2Fdownload%2Fquery-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "dev": true, - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/minimalistic-assert/download/minimalistic-assert-1.0.1.tgz", - "integrity": "sha1-LhlN4ERibUoQ5/f7wAznPoPk1cc=", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/minimalistic-crypto-utils/download/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz", - "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=", - "dev": true - }, - "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npm.taobao.org/minipass/download/minipass-3.1.3.tgz?cache=0&sync_timestamp=1589332828776&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminipass%2Fdownload%2Fminipass-3.1.3.tgz", - "integrity": "sha1-fUL/HzljVILhX5zbUxhN7r1YFf0=", - "dev": true, - "requires": { - "yallist": "^4.0.0" - }, - "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", - "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", - "dev": true - } - } - }, - "minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/minipass-collect/download/minipass-collect-1.0.2.tgz", - "integrity": "sha1-IrgTv3Rdxu26JXa5QAIq1u3Ixhc=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/minipass-flush/download/minipass-flush-1.0.5.tgz", - "integrity": "sha1-gucTXX6JpQ/+ZGEKeHlTxMTLs3M=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-pipeline": { - "version": "1.2.3", - "resolved": "https://registry.npm.taobao.org/minipass-pipeline/download/minipass-pipeline-1.2.3.tgz?cache=0&sync_timestamp=1589390980211&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminipass-pipeline%2Fdownload%2Fminipass-pipeline-1.2.3.tgz", - "integrity": "sha1-VfeDkwfXSFnW6K2pw+vnLOwhajQ=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/mississippi/download/mississippi-3.0.0.tgz", - "integrity": "sha1-6goykfl+C16HdrNj1fChLZTGcCI=", - "dev": true, - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - }, - "dependencies": { - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/from2/download/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - } - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/mixin-deep/download/mixin-deep-1.3.2.tgz", - "integrity": "sha1-ESC0PcNZp4Xc5ltVuC4lfM9HlWY=", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.5.tgz?cache=0&sync_timestamp=1587535418745&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmkdirp%2Fdownload%2Fmkdirp-0.5.5.tgz", - "integrity": "sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8=", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/move-concurrently/download/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/aproba/download/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", - "dev": true - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz", - "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", - "dev": true - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npm.taobao.org/multicast-dns/download/multicast-dns-6.2.3.tgz", - "integrity": "sha1-oOx72QVcQoL3kMPIL04o2zsxsik=", - "dev": true, - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/multicast-dns-service-types/download/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npm.taobao.org/mute-stream/download/mute-stream-0.0.8.tgz", - "integrity": "sha1-FjDEKyJR/4HiooPelqVJfqkuXg0=", - "dev": true - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npm.taobao.org/mz/download/mz-2.7.0.tgz", - "integrity": "sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI=", - "dev": true, - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npm.taobao.org/nan/download/nan-2.14.1.tgz?cache=0&sync_timestamp=1587495873856&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnan%2Fdownload%2Fnan-2.14.1.tgz", - "integrity": "sha1-174036MQW5FJTDFHCJMV7/iHSwE=", - "dev": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npm.taobao.org/nanomatch/download/nanomatch-1.2.13.tgz", - "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz", - "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", - "dev": true - } - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/natural-compare/download/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz", - "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=", - "dev": true - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npm.taobao.org/neo-async/download/neo-async-2.6.1.tgz?cache=0&sync_timestamp=1594317434347&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fneo-async%2Fdownload%2Fneo-async-2.6.1.tgz", - "integrity": "sha1-rCetpmFn+ohJpq3dg39rGJrSCBw=", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/nice-try/download/nice-try-1.0.5.tgz?cache=0&sync_timestamp=1584699756095&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnice-try%2Fdownload%2Fnice-try-1.0.5.tgz", - "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", - "dev": true - }, - "no-case": { - "version": "2.3.2", - "resolved": "https://registry.npm.taobao.org/no-case/download/no-case-2.3.2.tgz?cache=0&sync_timestamp=1576721537540&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fno-case%2Fdownload%2Fno-case-2.3.2.tgz", - "integrity": "sha1-YLgTOWvjmz8SiKTB7V0efSi0ZKw=", - "dev": true, - "requires": { - "lower-case": "^1.1.1" - } - }, - "node-cache": { - "version": "4.2.1", - "resolved": "https://registry.npm.taobao.org/node-cache/download/node-cache-4.2.1.tgz?cache=0&sync_timestamp=1593618846888&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-cache%2Fdownload%2Fnode-cache-4.2.1.tgz", - "integrity": "sha1-79hHTe5O3sQTjN3tWA9VFlAPczQ=", - "dev": true, - "requires": { - "clone": "2.x", - "lodash": "^4.17.15" - } - }, - "node-forge": { - "version": "0.9.0", - "resolved": "https://registry.npm.taobao.org/node-forge/download/node-forge-0.9.0.tgz", - "integrity": "sha1-1iQFDtu0SHStyhK7mlLsY8t4JXk=", - "dev": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/node-int64/download/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-ipc": { - "version": "9.1.1", - "resolved": "https://registry.npm.taobao.org/node-ipc/download/node-ipc-9.1.1.tgz", - "integrity": "sha1-TiRe1pOOZRAOWV68XcNLFujdXWk=", - "dev": true, - "requires": { - "event-pubsub": "4.3.0", - "js-message": "1.0.5", - "js-queue": "2.0.0" - } - }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/node-libs-browser/download/node-libs-browser-2.2.1.tgz", - "integrity": "sha1-tk9RPRgzhiX5A0bSew0jXmMfZCU=", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npm.taobao.org/util/download/util-0.11.1.tgz?cache=0&sync_timestamp=1588238331562&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futil%2Fdownload%2Futil-0.11.1.tgz", - "integrity": "sha1-MjZzNyDsZLsn9uJvQhqqLhtYjWE=", - "dev": true, - "requires": { - "inherits": "2.0.3" - } - } - } - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/node-modules-regexp/download/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "5.4.3", - "resolved": "https://registry.npm.taobao.org/node-notifier/download/node-notifier-5.4.3.tgz", - "integrity": "sha1-y3La+UyTkECY4oucWQ/YZuRkvVA=", - "dev": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, - "node-releases": { - "version": "1.1.59", - "resolved": "https://registry.npm.taobao.org/node-releases/download/node-releases-1.1.59.tgz?cache=0&sync_timestamp=1594212234909&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-releases%2Fdownload%2Fnode-releases-1.1.59.tgz", - "integrity": "sha1-TWSDMGQc7HBL/xD45P4o5FOrjo4=", - "dev": true - }, - "node-sass": { - "version": "4.14.1", - "resolved": "https://registry.npm.taobao.org/node-sass/download/node-sass-4.14.1.tgz?cache=0&sync_timestamp=1588635903344&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-sass%2Fdownload%2Fnode-sass-4.14.1.tgz", - "integrity": "sha1-mch+wu+3BH7WOPtMnbfzpC4iF7U=", - "dev": true, - "requires": { - "async-foreach": "^0.1.3", - "chalk": "^1.1.1", - "cross-spawn": "^3.0.0", - "gaze": "^1.0.0", - "get-stdin": "^4.0.1", - "glob": "^7.0.3", - "in-publish": "^2.0.0", - "lodash": "^4.17.15", - "meow": "^3.7.0", - "mkdirp": "^0.5.1", - "nan": "^2.13.2", - "node-gyp": "^3.8.0", - "npmlog": "^4.0.0", - "request": "^2.88.0", - "sass-graph": "2.2.5", - "stdout-stream": "^1.4.0", - "true-case-path": "^1.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-2.2.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-1.1.3.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "cross-spawn": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-3.0.1.tgz?cache=0&sync_timestamp=1590448522710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcross-spawn%2Fdownload%2Fcross-spawn-3.0.1.tgz", - "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427582110&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node-gyp": { - "version": "3.8.0", - "resolved": "https://registry.npm.taobao.org/node-gyp/download/node-gyp-3.8.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-gyp%2Fdownload%2Fnode-gyp-3.8.0.tgz", - "integrity": "sha1-VAMEJhwzDoDQ1e3OJTpoyzlkIYw=", - "dev": true, - "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "^2.87.0", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" - }, - "dependencies": { - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npm.taobao.org/fstream/download/fstream-1.0.12.tgz", - "integrity": "sha1-Touo7i1Ivk99DeUFRVVI6uWTIEU=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - } - } - }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npm.taobao.org/nopt/download/nopt-3.0.6.tgz?cache=0&sync_timestamp=1583704549918&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnopt%2Fdownload%2Fnopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-5.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-2.0.0.tgz?cache=0&sync_timestamp=1569557271992&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "tar": { - "version": "2.2.2", - "resolved": "https://registry.npm.taobao.org/tar/download/tar-2.2.2.tgz?cache=0&sync_timestamp=1588021389848&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftar%2Fdownload%2Ftar-2.2.2.tgz", - "integrity": "sha1-DKiEhWLHKZuLRG/2pNYM27I+3EA=", - "dev": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.12", - "inherits": "2" - }, - "dependencies": { - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npm.taobao.org/block-stream/download/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", - "dev": true, - "requires": { - "inherits": "~2.0.0" - } - }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npm.taobao.org/fstream/download/fstream-1.0.12.tgz", - "integrity": "sha1-Touo7i1Ivk99DeUFRVVI6uWTIEU=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - } - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, - "nopt": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/nopt/download/nopt-4.0.3.tgz?cache=0&sync_timestamp=1583704549918&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnopt%2Fdownload%2Fnopt-4.0.3.tgz", - "integrity": "sha1-o3XK2dAv2SEnjZVMIlTVqlfhXkg=", - "dev": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npm.taobao.org/normalize-package-data/download/normalize-package-data-2.5.0.tgz", - "integrity": "sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg=", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", - "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", - "dev": true - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/normalize-range/download/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true - }, - "normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npm.taobao.org/normalize-url/download/normalize-url-3.3.0.tgz", - "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=", - "dev": true - }, - "normalize-wheel": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/normalize-wheel/download/normalize-wheel-1.0.1.tgz", - "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" - }, - "normalize.css": { - "version": "8.0.1", - "resolved": "https://registry.npm.taobao.org/normalize.css/download/normalize.css-8.0.1.tgz", - "integrity": "sha1-m5iiCHOLnMJjTKrLxC0THJdIe/M=" - }, - "npm": { - "version": "6.14.5", - "resolved": "https://registry.npm.taobao.org/npm/download/npm-6.14.5.tgz?cache=0&sync_timestamp=1594140995939&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnpm%2Fdownload%2Fnpm-6.14.5.tgz", - "integrity": "sha1-LMWaMVjN2EYbSG0FhMdKtVRWchk=", - "requires": { - "JSONStream": "^1.3.5", - "abbrev": "~1.1.1", - "ansicolors": "~0.3.2", - "ansistyles": "~0.1.3", - "aproba": "^2.0.0", - "archy": "~1.0.0", - "bin-links": "^1.1.7", - "bluebird": "^3.5.5", - "byte-size": "^5.0.1", - "cacache": "^12.0.3", - "call-limit": "^1.1.1", - "chownr": "^1.1.4", - "ci-info": "^2.0.0", - "cli-columns": "^3.1.2", - "cli-table3": "^0.5.1", - "cmd-shim": "^3.0.3", - "columnify": "~1.5.4", - "config-chain": "^1.1.12", - "debuglog": "*", - "detect-indent": "~5.0.0", - "detect-newline": "^2.1.0", - "dezalgo": "~1.0.3", - "editor": "~1.0.0", - "figgy-pudding": "^3.5.1", - "find-npm-prefix": "^1.0.2", - "fs-vacuum": "~1.2.10", - "fs-write-stream-atomic": "~1.0.10", - "gentle-fs": "^2.3.0", - "glob": "^7.1.6", - "graceful-fs": "^4.2.4", - "has-unicode": "~2.0.1", - "hosted-git-info": "^2.8.8", - "iferr": "^1.0.2", - "imurmurhash": "*", - "infer-owner": "^1.0.4", - "inflight": "~1.0.6", - "inherits": "^2.0.4", - "ini": "^1.3.5", - "init-package-json": "^1.10.3", - "is-cidr": "^3.0.0", - "json-parse-better-errors": "^1.0.2", - "lazy-property": "~1.0.0", - "libcipm": "^4.0.7", - "libnpm": "^3.0.1", - "libnpmaccess": "^3.0.2", - "libnpmhook": "^5.0.3", - "libnpmorg": "^1.0.1", - "libnpmsearch": "^2.0.2", - "libnpmteam": "^1.0.2", - "libnpx": "^10.2.2", - "lock-verify": "^2.1.0", - "lockfile": "^1.0.4", - "lodash._baseindexof": "*", - "lodash._baseuniq": "~4.6.0", - "lodash._bindcallback": "*", - "lodash._cacheindexof": "*", - "lodash._createcache": "*", - "lodash._getnative": "*", - "lodash.clonedeep": "~4.5.0", - "lodash.restparam": "*", - "lodash.union": "~4.6.0", - "lodash.uniq": "~4.5.0", - "lodash.without": "~4.4.0", - "lru-cache": "^5.1.1", - "meant": "~1.0.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.5", - "move-concurrently": "^1.0.1", - "node-gyp": "^5.1.0", - "nopt": "^4.0.3", - "normalize-package-data": "^2.5.0", - "npm-audit-report": "^1.3.2", - "npm-cache-filename": "~1.0.2", - "npm-install-checks": "^3.0.2", - "npm-lifecycle": "^3.1.4", - "npm-package-arg": "^6.1.1", - "npm-packlist": "^1.4.8", - "npm-pick-manifest": "^3.0.2", - "npm-profile": "^4.0.4", - "npm-registry-fetch": "^4.0.4", - "npm-user-validate": "~1.0.0", - "npmlog": "~4.1.2", - "once": "~1.4.0", - "opener": "^1.5.1", - "osenv": "^0.1.5", - "pacote": "^9.5.12", - "path-is-inside": "~1.0.2", - "promise-inflight": "~1.0.1", - "qrcode-terminal": "^0.12.0", - "query-string": "^6.8.2", - "qw": "~1.0.1", - "read": "~1.0.7", - "read-cmd-shim": "^1.0.5", - "read-installed": "~4.0.3", - "read-package-json": "^2.1.1", - "read-package-tree": "^5.3.1", - "readable-stream": "^3.6.0", - "readdir-scoped-modules": "^1.1.0", - "request": "^2.88.0", - "retry": "^0.12.0", - "rimraf": "^2.7.1", - "safe-buffer": "^5.1.2", - "semver": "^5.7.1", - "sha": "^3.0.0", - "slide": "~1.1.6", - "sorted-object": "~2.0.1", - "sorted-union-stream": "~2.1.3", - "ssri": "^6.0.1", - "stringify-package": "^1.0.1", - "tar": "^4.4.13", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "uid-number": "0.0.6", - "umask": "~1.1.0", - "unique-filename": "^1.1.1", - "unpipe": "~1.0.0", - "update-notifier": "^2.5.0", - "uuid": "^3.3.3", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "~3.0.0", - "which": "^1.3.1", - "worker-farm": "^1.7.0", - "write-file-atomic": "^2.4.3" - }, - "dependencies": { - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "agentkeepalive": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", - "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", - "requires": { - "humanize-ms": "^1.2.1" - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", - "requires": { - "string-width": "^2.0.0" - } - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "ansicolors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=" - }, - "ansistyles": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz", - "integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=" - }, - "aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" - }, - "are-we-there-yet": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bin-links": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-1.1.7.tgz", - "integrity": "sha512-/eaLaTu7G7/o7PV04QPy1HRT65zf+1tFkPGv0sPTV0tRwufooYBQO3zrcyGgm+ja+ZtBf2GEuKjDRJ2pPG+yqA==", - "requires": { - "bluebird": "^3.5.3", - "cmd-shim": "^3.0.0", - "gentle-fs": "^2.3.0", - "graceful-fs": "^4.1.15", - "npm-normalize-package-bin": "^1.0.0", - "write-file-atomic": "^2.3.0" - } - }, - "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" - }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer-from": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==" - }, - "builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=" - }, - "byline": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", - "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=" - }, - "byte-size": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz", - "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==" - }, - "cacache": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", - "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "call-limit": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/call-limit/-/call-limit-1.1.1.tgz", - "integrity": "sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ==" - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "capture-stack-trace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - }, - "cidr-regex": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-2.0.10.tgz", - "integrity": "sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q==", - "requires": { - "ip-regex": "^2.1.0" - } - }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" - }, - "cli-columns": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cli-columns/-/cli-columns-3.1.2.tgz", - "integrity": "sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=", - "requires": { - "string-width": "^2.0.0", - "strip-ansi": "^3.0.1" - } - }, - "cli-table3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", - "requires": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", - "string-width": "^2.1.1" - } - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" - }, - "cmd-shim": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-3.0.3.tgz", - "integrity": "sha512-DtGg+0xiFhQIntSBRzL2fRQBnmtAVwXIDo4Qq46HPpObYquxMaZS4sb82U9nH91qJrlosC1wa9gwr0QyL/HypA==", - "requires": { - "graceful-fs": "^4.1.2", - "mkdirp": "~0.5.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "requires": { - "color-name": "^1.1.1" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colors": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", - "optional": true - }, - "columnify": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", - "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", - "requires": { - "strip-ansi": "^3.0.0", - "wcwidth": "^1.0.0" - } - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", - "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" - } - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" - }, - "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=" - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "requires": { - "clone": "^1.0.2" - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "detect-indent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", - "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=" - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" - }, - "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", - "requires": { - "is-obj": "^1.0.0" - } - }, - "dotenv": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", - "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "duplexify": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "optional": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "editor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", - "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" - }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "requires": { - "iconv-lite": "~0.4.13" - } - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "requires": { - "once": "^1.4.0" - } - }, - "env-paths": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", - "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==" - }, - "err-code": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", - "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "requires": { - "prr": "~1.0.1" - } - }, - "es-abstract": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", - "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "figgy-pudding": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", - "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" - }, - "find-npm-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz", - "integrity": "sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==" - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "^2.0.0" - } - }, - "flush-write-stream": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - } - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "requires": { - "minipass": "^2.6.0" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "fs-vacuum": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz", - "integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=", - "requires": { - "graceful-fs": "^4.1.2", - "path-is-inside": "^1.0.1", - "rimraf": "^2.5.2" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - }, - "dependencies": { - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "genfun": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", - "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==" - }, - "gentle-fs": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gentle-fs/-/gentle-fs-2.3.0.tgz", - "integrity": "sha512-3k2CgAmPxuz7S6nKK+AqFE2AdM1QuwqKLPKzIET3VRwK++3q96MsNFobScDjlCrq97ZJ8y5R725MOlm6ffUCjg==", - "requires": { - "aproba": "^1.1.2", - "chownr": "^1.1.2", - "cmd-shim": "^3.0.3", - "fs-vacuum": "^1.2.10", - "graceful-fs": "^4.1.11", - "iferr": "^0.1.5", - "infer-owner": "^1.0.4", - "mkdirp": "^0.5.1", - "path-is-inside": "^1.0.2", - "read-cmd-shim": "^1.0.1", - "slide": "^1.1.6" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" - } - } - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "requires": { - "ini": "^1.3.4" - } - }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - } - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", - "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", - "requires": { - "ajv": "^5.3.0", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" - }, - "http-cache-semantics": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" - }, - "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", - "requires": { - "agent-base": "4", - "debug": "3.1.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - } - }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "requires": { - "ms": "^2.0.0" - } - }, - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "iferr": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/iferr/download/iferr-1.0.2.tgz", - "integrity": "sha1-6f3kmp2gbcSkGUxsntbQgwUDem0=" - }, - "ignore-walk": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", - "requires": { - "minimatch": "^3.0.4" - } - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "init-package-json": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", - "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", - "requires": { - "glob": "^7.1.1", - "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", - "promzard": "^0.3.0", - "read": "~1.0.1", - "read-package-json": "1 || 2", - "semver": "2.x || 3.x || 4 || 5", - "validate-npm-package-license": "^3.0.1", - "validate-npm-package-name": "^3.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", - "requires": { - "ci-info": "^1.5.0" - }, - "dependencies": { - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" - } - } - }, - "is-cidr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-3.0.0.tgz", - "integrity": "sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q==", - "requires": { - "cidr-regex": "^2.0.10" - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" - } - }, - "is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "requires": { - "path-is-inside": "^1.0.1" - } - }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "requires": { - "has": "^1.0.1" - } - }, - "is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", - "requires": { - "package-json": "^4.0.0" - } - }, - "lazy-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz", - "integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=" - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "requires": { - "invert-kv": "^2.0.0" - } - }, - "libcipm": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/libcipm/-/libcipm-4.0.7.tgz", - "integrity": "sha512-fTq33otU3PNXxxCTCYCYe7V96o59v/o7bvtspmbORXpgFk+wcWrGf5x6tBgui5gCed/45/wtPomBsZBYm5KbIw==", - "requires": { - "bin-links": "^1.1.2", - "bluebird": "^3.5.1", - "figgy-pudding": "^3.5.1", - "find-npm-prefix": "^1.0.2", - "graceful-fs": "^4.1.11", - "ini": "^1.3.5", - "lock-verify": "^2.0.2", - "mkdirp": "^0.5.1", - "npm-lifecycle": "^3.0.0", - "npm-logical-tree": "^1.2.1", - "npm-package-arg": "^6.1.0", - "pacote": "^9.1.0", - "read-package-json": "^2.0.13", - "rimraf": "^2.6.2", - "worker-farm": "^1.6.0" - } - }, - "libnpm": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/libnpm/-/libnpm-3.0.1.tgz", - "integrity": "sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ==", - "requires": { - "bin-links": "^1.1.2", - "bluebird": "^3.5.3", - "find-npm-prefix": "^1.0.2", - "libnpmaccess": "^3.0.2", - "libnpmconfig": "^1.2.1", - "libnpmhook": "^5.0.3", - "libnpmorg": "^1.0.1", - "libnpmpublish": "^1.1.2", - "libnpmsearch": "^2.0.2", - "libnpmteam": "^1.0.2", - "lock-verify": "^2.0.2", - "npm-lifecycle": "^3.0.0", - "npm-logical-tree": "^1.2.1", - "npm-package-arg": "^6.1.0", - "npm-profile": "^4.0.2", - "npm-registry-fetch": "^4.0.0", - "npmlog": "^4.1.2", - "pacote": "^9.5.3", - "read-package-json": "^2.0.13", - "stringify-package": "^1.0.0" - } - }, - "libnpmaccess": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.2.tgz", - "integrity": "sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ==", - "requires": { - "aproba": "^2.0.0", - "get-stream": "^4.0.0", - "npm-package-arg": "^6.1.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpmconfig": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz", - "integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==", - "requires": { - "figgy-pudding": "^3.5.1", - "find-up": "^3.0.0", - "ini": "^1.3.5" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - } - } - }, - "libnpmhook": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/libnpmhook/-/libnpmhook-5.0.3.tgz", - "integrity": "sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA==", - "requires": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpmorg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/libnpmorg/-/libnpmorg-1.0.1.tgz", - "integrity": "sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww==", - "requires": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpmpublish": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.2.tgz", - "integrity": "sha512-2yIwaXrhTTcF7bkJKIKmaCV9wZOALf/gsTDxVSu/Gu/6wiG3fA8ce8YKstiWKTxSFNC0R7isPUb6tXTVFZHt2g==", - "requires": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.5.1", - "get-stream": "^4.0.0", - "lodash.clonedeep": "^4.5.0", - "normalize-package-data": "^2.4.0", - "npm-package-arg": "^6.1.0", - "npm-registry-fetch": "^4.0.0", - "semver": "^5.5.1", - "ssri": "^6.0.1" - } - }, - "libnpmsearch": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-2.0.2.tgz", - "integrity": "sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg==", - "requires": { - "figgy-pudding": "^3.5.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpmteam": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/libnpmteam/-/libnpmteam-1.0.2.tgz", - "integrity": "sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA==", - "requires": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpx": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/libnpx/-/libnpx-10.2.2.tgz", - "integrity": "sha512-ujaYToga1SAX5r7FU5ShMFi88CWpY75meNZtr6RtEyv4l2ZK3+Wgvxq2IqlwWBiDZOqhumdeiocPS1aKrCMe3A==", - "requires": { - "dotenv": "^5.0.1", - "npm-package-arg": "^6.0.0", - "rimraf": "^2.6.2", - "safe-buffer": "^5.1.0", - "update-notifier": "^2.3.0", - "which": "^1.3.0", - "y18n": "^4.0.0", - "yargs": "^11.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lock-verify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz", - "integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==", - "requires": { - "npm-package-arg": "^6.1.0", - "semver": "^5.4.1" - } - }, - "lockfile": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", - "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", - "requires": { - "signal-exit": "^3.0.2" - } - }, - "lodash._baseindexof": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", - "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=" - }, - "lodash._baseuniq": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", - "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=", - "requires": { - "lodash._createset": "~4.0.0", - "lodash._root": "~3.0.0" - } - }, - "lodash._bindcallback": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=" - }, - "lodash._cacheindexof": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", - "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=" - }, - "lodash._createcache": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", - "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=", - "requires": { - "lodash._getnative": "^3.0.0" - } - }, - "lodash._createset": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", - "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=" - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" - }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" - }, - "lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" - }, - "lodash.without": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz", - "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=" - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" - } - }, - "make-fetch-happen": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", - "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", - "requires": { - "agentkeepalive": "^3.4.1", - "cacache": "^12.0.0", - "http-cache-semantics": "^3.8.1", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "node-fetch-npm": "^2.0.2", - "promise-retry": "^1.1.1", - "socks-proxy-agent": "^4.0.0", - "ssri": "^6.0.0" - } - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "requires": { - "p-defer": "^1.0.0" - } - }, - "meant": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.1.tgz", - "integrity": "sha512-UakVLFjKkbbUwNWJ2frVLnnAtbb7D7DsloxRd3s/gDpI8rdv8W5Hp3NaDb+POBI1fQdeussER6NB8vpcRURvlg==" - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - } - } - }, - "mime-db": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", - "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" - }, - "mime-types": { - "version": "2.1.19", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", - "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", - "requires": { - "mime-db": "~1.35.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "requires": { - "minipass": "^2.9.0" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - } - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - } - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node-fetch-npm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", - "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", - "requires": { - "encoding": "^0.1.11", - "json-parse-better-errors": "^1.0.0", - "safe-buffer": "^5.1.1" - } - }, - "node-gyp": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz", - "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==", - "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "npmlog": "^4.1.2", - "request": "^2.88.0", - "rimraf": "^2.6.3", - "semver": "^5.7.1", - "tar": "^4.4.12", - "which": "^1.3.1" - } - }, - "nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "resolve": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", - "requires": { - "path-parse": "^1.0.6" - } - } - } - }, - "npm-audit-report": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-1.3.2.tgz", - "integrity": "sha512-abeqS5ONyXNaZJPGAf6TOUMNdSe1Y6cpc9MLBRn+CuUoYbfdca6AxOyXVlfIv9OgKX+cacblbG5w7A6ccwoTPw==", - "requires": { - "cli-table3": "^0.5.0", - "console-control-strings": "^1.1.0" - } - }, - "npm-bundled": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", - "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-cache-filename": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz", - "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=" - }, - "npm-install-checks": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.2.tgz", - "integrity": "sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg==", - "requires": { - "semver": "^2.3.0 || 3.x || 4 || 5" - } - }, - "npm-lifecycle": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.4.tgz", - "integrity": "sha512-tgs1PaucZwkxECGKhC/stbEgFyc3TGh2TJcg2CDr6jbvQRdteHNhmMeljRzpe4wgFAXQADoy1cSqqi7mtiAa5A==", - "requires": { - "byline": "^5.0.0", - "graceful-fs": "^4.1.15", - "node-gyp": "^5.0.2", - "resolve-from": "^4.0.0", - "slide": "^1.1.6", - "uid-number": "0.0.6", - "umask": "^1.1.0", - "which": "^1.3.1" - } - }, - "npm-logical-tree": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz", - "integrity": "sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg==" - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" - }, - "npm-package-arg": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", - "requires": { - "hosted-git-info": "^2.7.1", - "osenv": "^0.1.5", - "semver": "^5.6.0", - "validate-npm-package-name": "^3.0.0" - } - }, - "npm-packlist": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-pick-manifest": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", - "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", - "requires": { - "figgy-pudding": "^3.5.1", - "npm-package-arg": "^6.0.0", - "semver": "^5.4.1" - } - }, - "npm-profile": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz", - "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==", - "requires": { - "aproba": "^1.1.2 || 2", - "figgy-pudding": "^3.4.1", - "npm-registry-fetch": "^4.0.0" - } - }, - "npm-registry-fetch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.4.tgz", - "integrity": "sha512-6jb34hX/iYNQebqWUHtU8YF6Cjb1H6ouTFPClYsyiW6lpFkljTpdeftm53rRojtja1rKAvKNIIiTS5Sjpw4wsA==", - "requires": { - "JSONStream": "^1.3.4", - "bluebird": "^3.5.1", - "figgy-pudding": "^3.4.1", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "npm-package-arg": "^6.1.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - } - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "npm-user-validate": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.0.tgz", - "integrity": "sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE=" - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "opener": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", - "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==" - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - } - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" - }, - "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" - }, - "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - } - }, - "pacote": { - "version": "9.5.12", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz", - "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==", - "requires": { - "bluebird": "^3.5.3", - "cacache": "^12.0.2", - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "get-stream": "^4.1.0", - "glob": "^7.1.3", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "minimatch": "^3.0.4", - "minipass": "^2.3.5", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "normalize-package-data": "^2.4.0", - "npm-normalize-package-bin": "^1.0.0", - "npm-package-arg": "^6.1.0", - "npm-packlist": "^1.1.12", - "npm-pick-manifest": "^3.0.0", - "npm-registry-fetch": "^4.0.0", - "osenv": "^0.1.5", - "promise-inflight": "^1.0.1", - "promise-retry": "^1.1.1", - "protoduck": "^5.0.1", - "rimraf": "^2.6.2", - "safe-buffer": "^5.1.2", - "semver": "^5.6.0", - "ssri": "^6.0.1", - "tar": "^4.4.10", - "unique-filename": "^1.1.1", - "which": "^1.3.1" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", - "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" - }, - "promise-retry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", - "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", - "requires": { - "err-code": "^1.0.0", - "retry": "^0.10.0" - }, - "dependencies": { - "retry": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", - "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" - } - } - }, - "promzard": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", - "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", - "requires": { - "read": "1" - } - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" - }, - "protoduck": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", - "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", - "requires": { - "genfun": "^5.0.0" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "qrcode-terminal": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", - "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "query-string": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.2.tgz", - "integrity": "sha512-J3Qi8XZJXh93t2FiKyd/7Ec6GNifsjKXUsVFkSBj/kjLsDylWhnCz4NT1bkPcKotttPW+QbKGqqPH8OoI2pdqw==", - "requires": { - "decode-uri-component": "^0.2.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - } - }, - "qw": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/qw/-/qw-1.0.1.tgz", - "integrity": "sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=" - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - } - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "requires": { - "mute-stream": "~0.0.4" - } - }, - "read-cmd-shim": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz", - "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==", - "requires": { - "graceful-fs": "^4.1.2" - } - }, - "read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", - "requires": { - "debuglog": "^1.0.1", - "graceful-fs": "^4.1.2", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - } - }, - "read-package-json": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", - "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", - "requires": { - "glob": "^7.1.1", - "graceful-fs": "^4.1.2", - "json-parse-better-errors": "^1.0.1", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "read-package-tree": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", - "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", - "requires": { - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "util-promisify": "^2.1.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "requires": { - "rc": "^1.0.1" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "requires": { - "aproba": "^1.1.1" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", - "requires": { - "semver": "^5.0.3" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "sha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/sha/-/sha-3.0.0.tgz", - "integrity": "sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw==", - "requires": { - "graceful-fs": "^4.1.2" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" - }, - "smart-buffer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", - "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" - }, - "socks": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", - "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", - "requires": { - "ip": "1.1.5", - "smart-buffer": "^4.1.0" - } - }, - "socks-proxy-agent": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", - "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", - "requires": { - "agent-base": "~4.2.1", - "socks": "~2.3.2" - }, - "dependencies": { - "agent-base": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", - "requires": { - "es6-promisify": "^5.0.0" - } - } - } - }, - "sorted-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz", - "integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=" - }, - "sorted-union-stream": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz", - "integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=", - "requires": { - "from2": "^1.3.0", - "stream-iterate": "^1.1.0" - }, - "dependencies": { - "from2": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz", - "integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.10" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", - "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==" - }, - "split-on-first": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" - }, - "sshpk": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "stream-each": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", - "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-iterate": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz", - "integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=", - "requires": { - "readable-stream": "^2.1.5", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" - }, - "strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "stringify-package": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", - "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", - "requires": { - "execa": "^0.7.0" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" - }, - "tiny-relative-date": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz", - "integrity": "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==" - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "uid-number": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", - "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=" - }, - "umask": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", - "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=" - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", - "requires": { - "crypto-random-string": "^1.0.0" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" - }, - "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "requires": { - "prepend-http": "^1.0.1" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" - }, - "util-promisify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", - "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", - "requires": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", - "requires": { - "builtins": "^1.0.3" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "requires": { - "defaults": "^1.0.3" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "wide-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", - "requires": { - "string-width": "^1.0.2" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", - "requires": { - "string-width": "^2.1.1" - } - }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "requires": { - "errno": "~0.1.7" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" - }, - "yargs": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz", - "integrity": "sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==", - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - }, - "dependencies": { - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" - } - } - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npm.taobao.org/npmlog/download/npmlog-4.1.2.tgz", - "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/nprogress/download/nprogress-0.2.0.tgz?cache=0&sync_timestamp=1587262530340&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnprogress%2Fdownload%2Fnprogress-0.2.0.tgz", - "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/nth-check/download/nth-check-1.0.2.tgz", - "integrity": "sha1-sr0pXDfj3VijvwcAN2Zjuk2c8Fw=", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npm.taobao.org/num2fraction/download/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/number-is-nan/download/number-is-nan-1.0.1.tgz?cache=0&sync_timestamp=1581061562193&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnumber-is-nan%2Fdownload%2Fnumber-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/nwsapi/download/nwsapi-2.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnwsapi%2Fdownload%2Fnwsapi-2.2.0.tgz", - "integrity": "sha1-IEh5qePQaP8qVROcLHcngGgaOLc=", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz", - "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npm.taobao.org/object-copy/download/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "object-hash": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/object-hash/download/object-hash-1.3.1.tgz?cache=0&sync_timestamp=1582002911785&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-hash%2Fdownload%2Fobject-hash-1.3.1.tgz", - "integrity": "sha1-/eRSCYqVHLFF8Dm7fUVUSd3BJt8=", - "dev": true - }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npm.taobao.org/object-inspect/download/object-inspect-1.8.0.tgz?cache=0&sync_timestamp=1592545140756&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-inspect%2Fdownload%2Fobject-inspect-1.8.0.tgz", - "integrity": "sha1-34B+Xs9TpgnMa/6T6sPMe+WzqdA=" - }, - "object-is": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/object-is/download/object-is-1.1.2.tgz", - "integrity": "sha1-xdLof/nhGfeLegiEQVGeLuwVc7Y=", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/object-keys/download/object-keys-1.1.1.tgz", - "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/object-visit/download/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/object.assign/download/object.assign-4.1.0.tgz", - "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/object.getownpropertydescriptors/download/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha1-Npvx+VktiridcS3O1cuBx8U1Jkk=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/object.pick/download/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/object.values/download/object.values-1.1.1.tgz", - "integrity": "sha1-aKmezeNWt+kpWjxeDOMdyMlT3l4=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/obuf/download/obuf-1.1.2.tgz", - "integrity": "sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4=", - "dev": true - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/on-headers/download/on-headers-1.0.2.tgz", - "integrity": "sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-5.1.0.tgz", - "integrity": "sha1-//DzyRYX/mK7UBiWNumayKbfe+U=", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - }, - "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/mimic-fn/download/mimic-fn-2.1.0.tgz", - "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs=", - "dev": true - } - } - }, - "open": { - "version": "6.4.0", - "resolved": "https://registry.npm.taobao.org/open/download/open-6.4.0.tgz?cache=0&sync_timestamp=1589619927236&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fopen%2Fdownload%2Fopen-6.4.0.tgz", - "integrity": "sha1-XBPpbQ3IlGhhZPGJZez+iJ7PyKk=", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "opener": { - "version": "1.5.1", - "resolved": "https://registry.npm.taobao.org/opener/download/opener-1.5.1.tgz", - "integrity": "sha1-bS8Od/GgrwAyrKcWwsH7uOfoq+0=", - "dev": true - }, - "opn": { - "version": "5.5.0", - "resolved": "https://registry.npm.taobao.org/opn/download/opn-5.5.0.tgz", - "integrity": "sha1-/HFk+rVtI1kExRw7J9pnWMo7m/w=", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npm.taobao.org/optionator/download/optionator-0.8.3.tgz", - "integrity": "sha1-hPodA2/p08fiHZmIS2ARZ+yPtJU=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "ora": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/ora/download/ora-3.4.0.tgz?cache=0&sync_timestamp=1594997507229&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fora%2Fdownload%2Fora-3.4.0.tgz", - "integrity": "sha1-vwdSSRBZo+8+1MhQl1Md6f280xg=", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-spinners": "^2.0.0", - "log-symbols": "^2.2.0", - "strip-ansi": "^5.2.0", - "wcwidth": "^1.0.1" - }, - "dependencies": { - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/cli-cursor/download/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/restore-cursor/download/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - } - } - }, - "original": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/original/download/original-1.0.2.tgz", - "integrity": "sha1-5EKmHP/hxf0gpl8yYcJmY7MD8l8=", - "dev": true, - "requires": { - "url-parse": "^1.4.3" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/os-browserify/download/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/os-homedir/download/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/os-tmpdir/download/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npm.taobao.org/osenv/download/osenv-0.1.5.tgz", - "integrity": "sha1-hc36+uso6Gd/QW4odZK18/SepBA=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/p-each-series/download/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/p-finally/download/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/p-limit/download/p-limit-2.3.0.tgz?cache=0&sync_timestamp=1594559734248&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-limit%2Fdownload%2Fp-limit-2.3.0.tgz", - "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-3.0.0.tgz", - "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/p-map/download/p-map-3.0.0.tgz", - "integrity": "sha1-1wTZr4orpoTiYA2aIVmD1BQal50=", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/p-reduce/download/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true - }, - "p-retry": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/p-retry/download/p-retry-3.0.1.tgz?cache=0&sync_timestamp=1572521210242&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-retry%2Fdownload%2Fp-retry-3.0.1.tgz", - "integrity": "sha1-MWtMiJPiyNwc+okfQGxLQivr8yg=", - "dev": true, - "requires": { - "retry": "^0.12.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/p-try/download/p-try-2.2.0.tgz", - "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=" - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npm.taobao.org/pako/download/pako-1.0.11.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpako%2Fdownload%2Fpako-1.0.11.tgz", - "integrity": "sha1-bJWZ00DVTf05RjgCUqNXBaa5kr8=", - "dev": true - }, - "parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/parallel-transform/download/parallel-transform-1.2.0.tgz", - "integrity": "sha1-kEnKN9bLIYLDsdLHIL6U0UpYFPw=", - "dev": true, - "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "param-case": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/param-case/download/param-case-2.1.1.tgz", - "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", - "dev": true, - "requires": { - "no-case": "^2.2.0" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/parent-module/download/parent-module-1.0.1.tgz", - "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-asn1": { - "version": "5.1.5", - "resolved": "https://registry.npm.taobao.org/parse-asn1/download/parse-asn1-5.1.5.tgz", - "integrity": "sha1-ADJxND2ljclMrOSU+u89IUfs6g4=", - "dev": true, - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/parse-json/download/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/parse5/download/parse5-5.1.1.tgz", - "integrity": "sha1-9o5OW6GFKsLK3AD0VV//bCq7YXg=", - "dev": true - }, - "parse5-htmlparser2-tree-adapter": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/parse5-htmlparser2-tree-adapter/download/parse5-htmlparser2-tree-adapter-5.1.1.tgz", - "integrity": "sha1-6MdD1OkhlNUpPs3isIvjHmdGHLw=", - "dev": true, - "requires": { - "parse5": "^5.1.1" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz", - "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/pascalcase/download/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path": { - "version": "0.12.7", - "resolved": "https://registry.npm.taobao.org/path/download/path-0.12.7.tgz", - "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", - "requires": { - "process": "^0.11.1", - "util": "^0.10.3" - } - }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npm.taobao.org/path-browserify/download/path-browserify-0.0.1.tgz", - "integrity": "sha1-5sTd1+06onxoogzE5Q4aTug7vEo=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/path-dirname/download/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/path-is-inside/download/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/path-parse/download/path-parse-1.0.6.tgz", - "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/path-type/download/path-type-3.0.0.tgz", - "integrity": "sha1-zvMdyOCho7sNEFwM2Xzzv0f0428=", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/pbkdf2/download/pbkdf2-3.1.1.tgz?cache=0&sync_timestamp=1591275785449&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpbkdf2%2Fdownload%2Fpbkdf2-3.1.1.tgz", - "integrity": "sha1-y4cksPramEWWhW0abrr9NYRlS5Q=", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npm.taobao.org/picomatch/download/picomatch-2.2.2.tgz", - "integrity": "sha1-IfMz6ba46v8CRo9RRupAbTRfTa0=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/pinkie/download/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/pinkie-promise/download/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/pirates/download/pirates-4.0.1.tgz", - "integrity": "sha1-ZDqSyviUVm+RsrmG0sZpUKji+4c=", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-3.0.0.tgz", - "integrity": "sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/pn/download/pn-1.1.0.tgz", - "integrity": "sha1-4vTO8OIZ9GPBeas3Rj5OHs3Muvs=", - "dev": true - }, - "pnp-webpack-plugin": { - "version": "1.6.4", - "resolved": "https://registry.npm.taobao.org/pnp-webpack-plugin/download/pnp-webpack-plugin-1.6.4.tgz", - "integrity": "sha1-yXEaxNxIpoXauvyG+Lbdn434QUk=", - "dev": true, - "requires": { - "ts-pnp": "^1.1.6" - } - }, - "popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npm.taobao.org/popper.js/download/popper.js-1.16.1.tgz", - "integrity": "sha1-KiI8s9x7YhPXQOQDcr5A3kPmWxs=" - }, - "portfinder": { - "version": "1.0.26", - "resolved": "https://registry.npm.taobao.org/portfinder/download/portfinder-1.0.26.tgz", - "integrity": "sha1-R1ZY1WyjC+1yrH8TeO01C9G2TnA=", - "dev": true, - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz", - "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/posix-character-classes/download/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npm.taobao.org/postcss/download/postcss-7.0.32.tgz?cache=0&sync_timestamp=1591102406139&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss%2Fdownload%2Fpostcss-7.0.32.tgz", - "integrity": "sha1-QxDW7jRwU9o0M9sr5JKIPWLOxZ0=", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-calc": { - "version": "7.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-calc/download/postcss-calc-7.0.2.tgz?cache=0&sync_timestamp=1582014221563&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-calc%2Fdownload%2Fpostcss-calc-7.0.2.tgz", - "integrity": "sha1-UE780AjKAnMSBWiweSsWzc3oqsE=", - "dev": true, - "requires": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - } - }, - "postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/postcss-colormin/download/postcss-colormin-4.0.3.tgz", - "integrity": "sha1-rgYLzpPteUrHEmTwgTLVUJVr04E=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-convert-values/download/postcss-convert-values-4.0.1.tgz", - "integrity": "sha1-yjgT7U2g+BL51DcDWE5Enr4Ymn8=", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-discard-comments/download/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha1-H7q9LCRr/2qq15l7KwkY9NevQDM=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-discard-duplicates/download/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha1-P+EzzTyCKC5VD8myORdqkge3hOs=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-discard-empty/download/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha1-yMlR6fc+2UKAGUWERKAq2Qu592U=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-discard-overridden/download/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha1-ZSrvipZybwKfXj4AFG7npOdV/1c=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-load-config": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/postcss-load-config/download/postcss-load-config-2.1.0.tgz", - "integrity": "sha1-yE1pK3u3tB3c7ZTuYuirMbQXsAM=", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.0", - "import-cwd": "^2.0.0" - } - }, - "postcss-loader": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/postcss-loader/download/postcss-loader-3.0.0.tgz", - "integrity": "sha1-a5eUPkfHLYRfqeA/Jzdz1OjdbC0=", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "postcss": "^7.0.0", - "postcss-load-config": "^2.0.0", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npm.taobao.org/postcss-merge-longhand/download/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha1-YvSaE+Sg7gTnuY9CuxYGLKJUniQ=", - "dev": true, - "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/postcss-merge-rules/download/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha1-NivqT/Wh+Y5AdacTxsslrv75plA=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "dependencies": { - "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/dot-prop/download/dot-prop-5.2.0.tgz", - "integrity": "sha1-w07MKVVtxF8fTCJpe29JBODMT8s=", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-obj/download/is-obj-2.0.0.tgz", - "integrity": "sha1-Rz+wXZc3BeP9liBUUBjKjiLvSYI=", - "dev": true - }, - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.2.tgz?cache=0&sync_timestamp=1582039646348&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-3.1.2.tgz", - "integrity": "sha1-sxD1xMD9r3b5SQK7qjDbaqhPUnA=", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-minify-font-values/download/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha1-zUw0TM5HQ0P6xdgiBqssvLiv1aY=", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-minify-gradients/download/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha1-k7KcL/UJnFNe7NpWxKpuZlpmNHE=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-minify-params/download/postcss-minify-params-4.0.2.tgz", - "integrity": "sha1-a5zvAwwR41Jh+V9hjJADbWgNuHQ=", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-minify-selectors/download/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha1-4uXrQL/uUA0M2SQ1APX46kJi+9g=", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/dot-prop/download/dot-prop-5.2.0.tgz", - "integrity": "sha1-w07MKVVtxF8fTCJpe29JBODMT8s=", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-obj/download/is-obj-2.0.0.tgz", - "integrity": "sha1-Rz+wXZc3BeP9liBUUBjKjiLvSYI=", - "dev": true - }, - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.2.tgz?cache=0&sync_timestamp=1582039646348&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-3.1.2.tgz", - "integrity": "sha1-sxD1xMD9r3b5SQK7qjDbaqhPUnA=", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/postcss-modules-extract-imports/download/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha1-gYcZoa4doyX5gyRGsBE27rSTzX4=", - "dev": true, - "requires": { - "postcss": "^7.0.5" - } - }, - "postcss-modules-local-by-default": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-modules-local-by-default/download/postcss-modules-local-by-default-3.0.2.tgz", - "integrity": "sha1-6KZWG+kUqvPAUodjd1JMqQ27eRU=", - "dev": true, - "requires": { - "icss-utils": "^4.1.1", - "postcss": "^7.0.16", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.0" - } - }, - "postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/postcss-modules-scope/download/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha1-OFyuATzHdD9afXYC0Qc6iequYu4=", - "dev": true, - "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" - } - }, - "postcss-modules-values": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/postcss-modules-values/download/postcss-modules-values-3.0.0.tgz", - "integrity": "sha1-W1AA1uuuKbQlUwG0o6VFdEI+fxA=", - "dev": true, - "requires": { - "icss-utils": "^4.0.0", - "postcss": "^7.0.6" - } - }, - "postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-charset/download/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha1-izWt067oOhNrBHHg1ZvlilAoXdQ=", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-display-values/download/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha1-Db4EpM6QY9RmftK+R2u4MMglk1o=", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-positions/download/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha1-BfdX+E8mBDc3g2ipH4ky1LECkX8=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-repeat-style/download/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha1-xOu8KJ85kaAo1EdRy90RkYsXkQw=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-string/download/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha1-zUTECrB6DHo23F6Zqs4eyk7CaQw=", - "dev": true, - "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-timing-functions/download/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha1-jgCcoqOUnNr4rSPmtquZy159KNk=", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-unicode/download/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha1-hBvUj9zzAZrUuqdJOj02O1KuHPs=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-url/download/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha1-EOQ3+GvHx+WPe5ZS7YeNqqlfquE=", - "dev": true, - "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-normalize-whitespace/download/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha1-vx1AcP5Pzqh9E0joJdjMDF+qfYI=", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npm.taobao.org/postcss-ordered-values/download/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha1-DPdcgg7H1cTSgBiVWeC1ceusDu4=", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/postcss-reduce-initial/download/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha1-f9QuvqXpyBRgljniwuhK4nC6SN8=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-reduce-transforms/download/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha1-F++kBerMbge+NBSlyi0QdGgdTik=", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-selector-parser": { - "version": "6.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-6.0.2.tgz?cache=0&sync_timestamp=1582039646348&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-6.0.2.tgz", - "integrity": "sha1-k0z3mdAWyDQRhZ4J3Oyt4BKG7Fw=", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "postcss-svgo": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/postcss-svgo/download/postcss-svgo-4.0.2.tgz", - "integrity": "sha1-F7mXvHEbMzurFDqu07jT1uPTglg=", - "dev": true, - "requires": { - "is-svg": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz", - "integrity": "sha1-n/giVH4okyE88cMO+lGsX9G6goE=", - "dev": true - } - } - }, - "postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/postcss-unique-selectors/download/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha1-lEaRHzKJv9ZMbWgPBzwDsfnuS6w=", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - } - }, - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-4.1.0.tgz", - "integrity": "sha1-RD9qIM7WSBor2k+oUypuVdeJoss=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/prepend-http/download/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npm.taobao.org/prettier/download/prettier-1.19.1.tgz", - "integrity": "sha1-99f1/4qc2HKnvkyhQglZVqYHl8s=", - "dev": true, - "optional": true - }, - "pretty": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/pretty/download/pretty-2.0.0.tgz", - "integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=", - "dev": true, - "requires": { - "condense-newlines": "^0.2.1", - "extend-shallow": "^2.0.1", - "js-beautify": "^1.6.12" - } - }, - "pretty-error": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/pretty-error/download/pretty-error-2.1.1.tgz", - "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", - "dev": true, - "requires": { - "renderkid": "^2.0.1", - "utila": "~0.4" - } - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npm.taobao.org/pretty-format/download/pretty-format-24.9.0.tgz?cache=0&sync_timestamp=1592926442295&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpretty-format%2Fdownload%2Fpretty-format-24.9.0.tgz", - "integrity": "sha1-EvrDGzcBmk7qPBGqmpWet2KKp8k=", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", - "dev": true - } - } - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npm.taobao.org/process/download/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz", - "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/progress/download/progress-2.0.3.tgz", - "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/promise-inflight/download/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true - }, - "prompts": { - "version": "2.3.2", - "resolved": "https://registry.npm.taobao.org/prompts/download/prompts-2.3.2.tgz", - "integrity": "sha1-SAVy2J7POVZtK9P+LJ/Mt8TAsGg=", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.4" - } - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npm.taobao.org/proto-list/download/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true - }, - "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.6.tgz", - "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", - "dev": true, - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.1" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npm.taobao.org/psl/download/psl-1.8.0.tgz", - "integrity": "sha1-kyb4vPsBOtzABf3/BWrM4CDlHCQ=", - "dev": true - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/public-encrypt/download/public-encrypt-4.0.3.tgz", - "integrity": "sha1-T8ydd6B+SLp1J+fL4N4z0HATMeA=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npm.taobao.org/bn.js/download/bn.js-4.11.9.tgz", - "integrity": "sha1-JtVWgpRY+dHoH8SJUkk9C6NQeCg=", - "dev": true - } - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", - "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npm.taobao.org/pumpify/download/pumpify-1.5.1.tgz?cache=0&sync_timestamp=1569938140182&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpumpify%2Fdownload%2Fpumpify-1.5.1.tgz", - "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/pump/download/pump-2.0.1.tgz", - "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz", - "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", - "dev": true - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npm.taobao.org/q/download/q-1.5.1.tgz?cache=0&sync_timestamp=1566282953114&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fq%2Fdownload%2Fq-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz", - "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=", - "dev": true - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/querystring/download/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/querystring-es3/download/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "querystringify": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/querystringify/download/querystringify-2.1.1.tgz", - "integrity": "sha1-YOWl/WSn+L+k0qsu1v30yFutFU4=", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz", - "integrity": "sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/randomfill/download/randomfill-1.0.4.tgz", - "integrity": "sha1-ySGW/IarQr6YPxvzF3giSTHWFFg=", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npm.taobao.org/range-parser/download/range-parser-1.2.1.tgz", - "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=", - "dev": true - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npm.taobao.org/raw-body/download/raw-body-2.4.0.tgz", - "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", - "dev": true, - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npm.taobao.org/react-is/download/react-is-16.13.1.tgz?cache=0&sync_timestamp=1595005282006&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-is%2Fdownload%2Freact-is-16.13.1.tgz", - "integrity": "sha1-eJcppNw23imZ3BVt1sHZwYzqVqQ=", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/read-pkg/download/read-pkg-5.2.0.tgz", - "integrity": "sha1-e/KVQ4yloz5WzTDgU7NO5yUMk8w=", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/parse-json/download/parse-json-5.0.0.tgz", - "integrity": "sha1-c+URTJhtFD76NxLU6iTbmkJm9g8=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" - } - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npm.taobao.org/type-fest/download/type-fest-0.6.0.tgz?cache=0&sync_timestamp=1593290909259&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftype-fest%2Fdownload%2Ftype-fest-0.6.0.tgz", - "integrity": "sha1-jSojcNPfiG61yQraHFv2GIrPg4s=", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/read-pkg-up/download/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/path-type/download/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/read-pkg/download/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - } - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.7.tgz", - "integrity": "sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz?cache=0&sync_timestamp=1589129378619&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-2.2.1.tgz", - "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/realpath-native/download/realpath-native-1.1.0.tgz?cache=0&sync_timestamp=1588859532761&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frealpath-native%2Fdownload%2Frealpath-native-1.1.0.tgz", - "integrity": "sha1-IAMpT+oj+wZy8kduviL89Jii1lw=", - "dev": true, - "requires": { - "util.promisify": "^1.0.0" - } - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/redent/download/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - }, - "dependencies": { - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/strip-indent/download/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" - } - } - } - }, - "regenerate": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/regenerate/download/regenerate-1.4.1.tgz", - "integrity": "sha1-ytkq2Oa1kXc0hfvgWkhcr09Ffm8=", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npm.taobao.org/regenerate-unicode-properties/download/regenerate-unicode-properties-8.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerate-unicode-properties%2Fdownload%2Fregenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha1-5d5xEdZV57pgwFfb6f83yH5lzew=", - "dev": true, - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.10.5.tgz?cache=0&sync_timestamp=1584052597708&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npm.taobao.org/regenerator-transform/download/regenerator-transform-0.14.5.tgz?cache=0&sync_timestamp=1593557570099&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-transform%2Fdownload%2Fregenerator-transform-0.14.5.tgz", - "integrity": "sha1-yY2hVGg2ccnE3LFuznNlF+G3/rQ=", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/regex-not/download/regex-not-1.0.2.tgz", - "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/regexp.prototype.flags/download/regexp.prototype.flags-1.3.0.tgz?cache=0&sync_timestamp=1576388141321&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregexp.prototype.flags%2Fdownload%2Fregexp.prototype.flags-1.3.0.tgz", - "integrity": "sha1-erqJs8E6ZFCdq888qNn7ub31y3U=", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/regexpp/download/regexpp-2.0.1.tgz?cache=0&sync_timestamp=1586019108913&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregexpp%2Fdownload%2Fregexpp-2.0.1.tgz", - "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", - "dev": true - }, - "regexpu-core": { - "version": "4.7.0", - "resolved": "https://registry.npm.taobao.org/regexpu-core/download/regexpu-core-4.7.0.tgz", - "integrity": "sha1-/L9FjFBDGwu3tF1pZ7gZLZHz2Tg=", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" - } - }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npm.taobao.org/regjsgen/download/regjsgen-0.5.2.tgz", - "integrity": "sha1-kv8pX7He7L9uzaslQ9IH6RqjNzM=", - "dev": true - }, - "regjsparser": { - "version": "0.6.4", - "resolved": "https://registry.npm.taobao.org/regjsparser/download/regjsparser-0.6.4.tgz", - "integrity": "sha1-p2n4aEMIQBpm6bUp0kNv9NBmYnI=", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npm.taobao.org/jsesc/download/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npm.taobao.org/relateurl/download/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "renderkid": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/renderkid/download/renderkid-2.0.3.tgz", - "integrity": "sha1-OAF5wv9a4TZcUivy/Pz/AcW3QUk=", - "dev": true, - "requires": { - "css-select": "^1.1.0", - "dom-converter": "^0.2", - "htmlparser2": "^3.3.0", - "strip-ansi": "^3.0.0", - "utila": "^0.4.0" - }, - "dependencies": { - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/css-select/download/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "dev": true, - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/css-what/download/css-what-2.1.3.tgz", - "integrity": "sha1-ptdgRXM2X+dGhsPzEcVlE9iChfI=", - "dev": true - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npm.taobao.org/domutils/download/domutils-1.5.1.tgz?cache=0&sync_timestamp=1589053312321&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomutils%2Fdownload%2Fdomutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.3.tgz", - "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/repeating/download/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npm.taobao.org/request/download/request-2.88.2.tgz", - "integrity": "sha1-1zyRhzHLWofaBH4gcjQUb2ZNErM=", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz", - "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=", - "dev": true - } - } - }, - "request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/request-promise-core/download/request-promise-core-1.1.3.tgz", - "integrity": "sha1-6aPAgbUTgN/qZ3M2Bh/qh5qCnuk=", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "request-promise-native": { - "version": "1.0.8", - "resolved": "https://registry.npm.taobao.org/request-promise-native/download/request-promise-native-1.0.8.tgz?cache=0&sync_timestamp=1572829683581&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frequest-promise-native%2Fdownload%2Frequest-promise-native-1.0.8.tgz", - "integrity": "sha1-pFW5YLgm5E4r+Jma9k3/K/5YyzY=", - "dev": true, - "requires": { - "request-promise-core": "1.1.3", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/require-main-filename/download/require-main-filename-2.0.0.tgz", - "integrity": "sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs=" - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "resize-observer-polyfill": { - "version": "1.5.1", - "resolved": "https://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz", - "integrity": "sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ=" - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npm.taobao.org/resolve/download/resolve-1.17.0.tgz", - "integrity": "sha1-sllBtUloIxzC0bt2p5y38sC/hEQ=", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/resolve-cwd/download/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/resolve-from/download/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/resolve-url/download/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/restore-cursor/download/restore-cursor-3.1.0.tgz", - "integrity": "sha1-OfZ8VLOnpYzqUjbZXPADQjljH34=", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npm.taobao.org/ret/download/ret-0.1.15.tgz", - "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", - "dev": true - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npm.taobao.org/retry/download/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true - }, - "rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/rgb-regex/download/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", - "dev": true - }, - "rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/rgba-regex/download/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-2.7.1.tgz?cache=0&sync_timestamp=1581229865753&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-2.7.1.tgz", - "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/ripemd160/download/ripemd160-2.0.2.tgz", - "integrity": "sha1-ocGm9iR1FXe6XQeRTLyShQWFiQw=", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npm.taobao.org/rsvp/download/rsvp-4.8.5.tgz", - "integrity": "sha1-yPFVMR0Wf2jyHhaN9x7FsIMRNzQ=", - "dev": true - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npm.taobao.org/run-async/download/run-async-2.4.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frun-async%2Fdownload%2Frun-async-2.4.1.tgz", - "integrity": "sha1-hEDsz5nqPnC9QJ1JqriOEMGJpFU=", - "dev": true - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/run-queue/download/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dev": true, - "requires": { - "aproba": "^1.1.1" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/aproba/download/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", - "dev": true - } - } - }, - "rxjs": { - "version": "6.6.0", - "resolved": "https://registry.npm.taobao.org/rxjs/download/rxjs-6.6.0.tgz?cache=0&sync_timestamp=1593794895607&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frxjs%2Fdownload%2Frxjs-6.6.0.tgz", - "integrity": "sha1-rykB7t8C46g/+n+IYkD/kBi77IQ=", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz?cache=0&sync_timestamp=1589129378619&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.2.1.tgz", - "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/safe-regex/download/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", - "dev": true - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/sane/download/sane-4.1.0.tgz", - "integrity": "sha1-7Ygf2SJzOmxGG8GJ3CtsAG8//e0=", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - } - }, - "sass-graph": { - "version": "2.2.5", - "resolved": "https://registry.npm.taobao.org/sass-graph/download/sass-graph-2.2.5.tgz", - "integrity": "sha1-qYHIdEa4MZ2W3OBnHkh4eb0kwug=", - "dev": true, - "requires": { - "glob": "^7.0.0", - "lodash": "^4.0.0", - "scss-tokenizer": "^0.2.3", - "yargs": "^13.3.2" - } - }, - "sass-loader": { - "version": "8.0.2", - "resolved": "https://registry.npm.taobao.org/sass-loader/download/sass-loader-8.0.2.tgz?cache=0&sync_timestamp=1594134284232&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsass-loader%2Fdownload%2Fsass-loader-8.0.2.tgz", - "integrity": "sha1-3r7NjDziQ8dkVPLoKQSCFQOACQ0=", - "dev": true, - "requires": { - "clone-deep": "^4.0.1", - "loader-utils": "^1.2.3", - "neo-async": "^2.6.1", - "schema-utils": "^2.6.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - } - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", - "dev": true - }, - "saxes": { - "version": "3.1.11", - "resolved": "https://registry.npm.taobao.org/saxes/download/saxes-3.1.11.tgz", - "integrity": "sha1-1Z0f0zLskq2YouCy7mRHAjhLHFs=", - "dev": true, - "requires": { - "xmlchars": "^2.1.1" - } - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-2.7.0.tgz", - "integrity": "sha1-FxUfdtjq5n+793lgwzxnatn078c=", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, - "scss-tokenizer": { - "version": "0.2.3", - "resolved": "https://registry.npm.taobao.org/scss-tokenizer/download/scss-tokenizer-0.2.3.tgz", - "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", - "dev": true, - "requires": { - "js-base64": "^2.1.8", - "source-map": "^0.4.2" - }, - "dependencies": { - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "selfsigned": { - "version": "1.10.7", - "resolved": "https://registry.npm.taobao.org/selfsigned/download/selfsigned-1.10.7.tgz", - "integrity": "sha1-2lgZ/QSdVXTyjoipvMbbxubzkGs=", - "dev": true, - "requires": { - "node-forge": "0.9.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", - "dev": true - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npm.taobao.org/send/download/send-0.17.1.tgz", - "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz?cache=0&sync_timestamp=1590596706367&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime%2Fdownload%2Fmime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", - "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz", - "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=", - "dev": true - } - } - }, - "serialize-javascript": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-3.1.0.tgz", - "integrity": "sha1-i/OpFwcSZk7yVhtEtpHq/jmSFOo=", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npm.taobao.org/serve-index/download/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz?cache=0&sync_timestamp=1593407647372&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz", - "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", - "dev": true - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npm.taobao.org/serve-static/download/serve-static-1.14.1.tgz", - "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/set-blocking/download/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/set-value/download/set-value-2.0.1.tgz?cache=0&sync_timestamp=1585774774019&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fset-value%2Fdownload%2Fset-value-2.0.1.tgz", - "integrity": "sha1-oY1AUw5vB95CKMfe/kInr4ytAFs=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/setimmediate/download/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz", - "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=", - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npm.taobao.org/sha.js/download/sha.js-2.4.11.tgz", - "integrity": "sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/shallow-clone/download/shallow-clone-3.0.1.tgz", - "integrity": "sha1-jymBrZJTH1UDWwH7IwdppA4C76M=", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz", - "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", - "dev": true - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshebang-command%2Fdownload%2Fshebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shell-quote": { - "version": "1.7.2", - "resolved": "https://registry.npm.taobao.org/shell-quote/download/shell-quote-1.7.2.tgz", - "integrity": "sha1-Z6fQLHbJ2iT5nSCAj8re0ODgS+I=", - "dev": true - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npm.taobao.org/shellwords/download/shellwords-0.1.1.tgz", - "integrity": "sha1-1rkYHBpI05cyTISHHvvPxz/AZUs=", - "dev": true - }, - "showdown": { - "version": "1.9.1", - "resolved": "https://registry.npm.taobao.org/showdown/download/showdown-1.9.1.tgz", - "integrity": "sha1-E04UjnXNRiPgnCGwURl315ta0O8=", - "requires": { - "yargs": "^14.2" - }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "yargs": { - "version": "14.2.3", - "resolved": "https://registry.npm.taobao.org/yargs/download/yargs-14.2.3.tgz?cache=0&sync_timestamp=1594421142336&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-14.2.3.tgz", - "integrity": "sha1-Ghw+3O0a+yov6jNgS8bR2NaIpBQ=", - "requires": { - "cliui": "^5.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^15.0.1" - } - }, - "yargs-parser": { - "version": "15.0.1", - "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-15.0.1.tgz?cache=0&sync_timestamp=1595125126126&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-15.0.1.tgz", - "integrity": "sha1-VHhq9AuCDcsvuAJbEbTWWddjI7M=", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/sigmund/download/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.3.tgz", - "integrity": "sha1-oUEMLt2PB3sItOJTyOrPyvBXRhw=", - "dev": true - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npm.taobao.org/simple-swizzle/download/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.3.2.tgz", - "integrity": "sha1-RXSirlb3qyBolvtDHq7tBm/fjwM=", - "dev": true - } - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/sisteransi/download/sisteransi-1.0.5.tgz", - "integrity": "sha1-E01oEpd1ZDfMBcoBNw06elcQde0=", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/slash/download/slash-2.0.0.tgz", - "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/slice-ansi/download/slice-ansi-2.1.0.tgz", - "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npm.taobao.org/snapdragon/download/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/snapdragon-node/download/snapdragon-node-2.1.1.tgz", - "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-descriptor/download/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz", - "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", - "dev": true - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/snapdragon-util/download/snapdragon-util-3.0.1.tgz", - "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - } - }, - "sockjs": { - "version": "0.3.20", - "resolved": "https://registry.npm.taobao.org/sockjs/download/sockjs-0.3.20.tgz", - "integrity": "sha1-smooPsVi74smh7RAM6Tuzqx12FU=", - "dev": true, - "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.4.0", - "websocket-driver": "0.6.5" - } - }, - "sockjs-client": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/sockjs-client/download/sockjs-client-1.4.0.tgz", - "integrity": "sha1-yfJWjhnI/YFztJl+o0IOC7MGx9U=", - "dev": true, - "requires": { - "debug": "^3.2.5", - "eventsource": "^1.0.7", - "faye-websocket": "~0.11.1", - "inherits": "^2.0.3", - "json3": "^3.3.2", - "url-parse": "^1.4.3" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz", - "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "faye-websocket": { - "version": "0.11.3", - "resolved": "https://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.11.3.tgz", - "integrity": "sha1-XA6aiWjokSwoZjn96XeosgnyUI4=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - } - } - }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/sort-keys/download/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz", - "integrity": "sha1-OZO9hzv8SEecyp6jpUeDXHwVSzQ=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npm.taobao.org/source-map-resolve/download/source-map-resolve-0.5.3.tgz?cache=0&sync_timestamp=1584829593933&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map-resolve%2Fdownload%2Fsource-map-resolve-0.5.3.tgz", - "integrity": "sha1-GQhmvs51U+H48mei7oLGBrVQmho=", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npm.taobao.org/source-map-support/download/source-map-support-0.5.19.tgz", - "integrity": "sha1-qYti+G3K9PZzmWSMCFKRq56P7WE=", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/source-map-url/download/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/spdx-correct/download/spdx-correct-3.1.1.tgz", - "integrity": "sha1-3s6BrJweZxPl99G28X1Gj6U9iak=", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/spdx-exceptions/download/spdx-exceptions-2.3.0.tgz?cache=0&sync_timestamp=1587450317950&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fspdx-exceptions%2Fdownload%2Fspdx-exceptions-2.3.0.tgz", - "integrity": "sha1-PyjOGnegA3JoPq3kpDMYNSeiFj0=", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/spdx-expression-parse/download/spdx-expression-parse-3.0.1.tgz?cache=0&sync_timestamp=1589389668441&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fspdx-expression-parse%2Fdownload%2Fspdx-expression-parse-3.0.1.tgz", - "integrity": "sha1-z3D1BILu/cmOPOCmgz5KU87rpnk=", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npm.taobao.org/spdx-license-ids/download/spdx-license-ids-3.0.5.tgz", - "integrity": "sha1-NpS1gEVnpFjTyARYQqY1hjL2JlQ=", - "dev": true - }, - "spdy": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/spdy/download/spdy-4.0.2.tgz?cache=0&sync_timestamp=1585970558936&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fspdy%2Fdownload%2Fspdy-4.0.2.tgz", - "integrity": "sha1-t09GYgOj7aRSwCSSuR+56EonZ3s=", - "dev": true, - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/spdy-transport/download/spdy-transport-3.0.0.tgz", - "integrity": "sha1-ANSGOmQArXXfkzYaFghgXl3NzzE=", - "dev": true, - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/split-string/download/split-string-3.1.0.tgz", - "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npm.taobao.org/sshpk/download/sshpk-1.16.1.tgz", - "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npm.taobao.org/ssri/download/ssri-6.0.1.tgz", - "integrity": "sha1-KjxBso3UW2K2Nnbst0ABJlrp7dg=", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npm.taobao.org/stable/download/stable-0.1.8.tgz", - "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88=", - "dev": true - }, - "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/stack-utils/download/stack-utils-1.0.2.tgz", - "integrity": "sha1-M+ujiXeIVYvr/C2wWdwVjsNs67g=", - "dev": true - }, - "stackframe": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/stackframe/download/stackframe-1.2.0.tgz?cache=0&sync_timestamp=1590854170093&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstackframe%2Fdownload%2Fstackframe-1.2.0.tgz", - "integrity": "sha1-UkKUktY8YuuYmATBFVLj0i53kwM=", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/static-extend/download/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz?cache=0&sync_timestamp=1587328410122&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstatuses%2Fdownload%2Fstatuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "stdout-stream": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/stdout-stream/download/stdout-stream-1.4.1.tgz", - "integrity": "sha1-WsF0zdXNcmEEqgwLK9g4FdjVNd4=", - "dev": true, - "requires": { - "readable-stream": "^2.0.1" - } - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/stealthy-require/download/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/stream-browserify/download/stream-browserify-2.0.2.tgz", - "integrity": "sha1-h1IdOKRKp+6RzhzSpH3wy0ndZgs=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npm.taobao.org/stream-each/download/stream-each-1.2.3.tgz", - "integrity": "sha1-6+J6DDibBPvMIzZClS4Qcxr6m64=", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npm.taobao.org/stream-http/download/stream-http-2.8.3.tgz?cache=0&sync_timestamp=1588702237891&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstream-http%2Fdownload%2Fstream-http-2.8.3.tgz", - "integrity": "sha1-stJCRpKIpaJ+xP6JM6z2I95lFPw=", - "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/stream-shift/download/stream-shift-1.0.1.tgz", - "integrity": "sha1-1wiCgVWasneEJCebCHfaPDktWj0=", - "dev": true - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/string-length/download/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-4.0.0.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/string.prototype.trimend/download/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha1-hYEqa4R6wAInD1gIFGBkyZX7aRM=", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/string.prototype.trimstart/download/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha1-FK9tnzSwU/fPyJty+PLuFLkDmlQ=", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.3.0.tgz", - "integrity": "sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4=", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", - "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz?cache=0&sync_timestamp=1570188570027&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-regex%2Fdownload%2Fansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=" - } - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/strip-bom/download/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/strip-eof/download/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/strip-final-newline/download/strip-final-newline-2.0.0.tgz", - "integrity": "sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0=", - "dev": true - }, - "strip-indent": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/strip-indent/download/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-2.0.1.tgz?cache=0&sync_timestamp=1594567532500&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "stylehacks": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/stylehacks/download/stylehacks-4.0.3.tgz", - "integrity": "sha1-Zxj8r00eB9ihMYaQiB6NlnJqcdU=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/dot-prop/download/dot-prop-5.2.0.tgz", - "integrity": "sha1-w07MKVVtxF8fTCJpe29JBODMT8s=", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-obj/download/is-obj-2.0.0.tgz", - "integrity": "sha1-Rz+wXZc3BeP9liBUUBjKjiLvSYI=", - "dev": true - }, - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-3.1.2.tgz?cache=0&sync_timestamp=1582039646348&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-3.1.2.tgz", - "integrity": "sha1-sxD1xMD9r3b5SQK7qjDbaqhPUnA=", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-6.1.0.tgz?cache=0&sync_timestamp=1569557271992&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-6.1.0.tgz", - "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/svg-tags/download/svg-tags-1.0.0.tgz", - "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", - "dev": true - }, - "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/svgo/download/svgo-1.3.2.tgz", - "integrity": "sha1-ttxRHAYzRsnkFbgeQ0ARRbltQWc=", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npm.taobao.org/symbol-tree/download/symbol-tree-3.2.4.tgz", - "integrity": "sha1-QwY30ki6d+B4iDlR+5qg7tfGP6I=", - "dev": true - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npm.taobao.org/table/download/table-5.4.6.tgz", - "integrity": "sha1-EpLRlQDOP4YFOwXw6Ofko7shB54=", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/tapable/download/tapable-1.1.3.tgz?cache=0&sync_timestamp=1589549614535&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftapable%2Fdownload%2Ftapable-1.1.3.tgz", - "integrity": "sha1-ofzMBrWNth/XpF2i2kT186Pme6I=", - "dev": true - }, - "terser": { - "version": "4.8.0", - "resolved": "https://registry.npm.taobao.org/terser/download/terser-4.8.0.tgz?cache=0&sync_timestamp=1593953638544&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser%2Fdownload%2Fterser-4.8.0.tgz", - "integrity": "sha1-YwVjQ9fHC7KfOvZlhlpG/gOg3xc=", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - } - }, - "terser-webpack-plugin": { - "version": "2.3.7", - "resolved": "https://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-2.3.7.tgz?cache=0&sync_timestamp=1594912432309&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser-webpack-plugin%2Fdownload%2Fterser-webpack-plugin-2.3.7.tgz", - "integrity": "sha1-SRD/XRqHIWjMf6bNN0nisNYKigs=", - "dev": true, - "requires": { - "cacache": "^13.0.1", - "find-cache-dir": "^3.3.1", - "jest-worker": "^25.4.0", - "p-limit": "^2.3.0", - "schema-utils": "^2.6.6", - "serialize-javascript": "^3.1.0", - "source-map": "^0.6.1", - "terser": "^4.6.12", - "webpack-sources": "^1.4.3" - }, - "dependencies": { - "cacache": { - "version": "13.0.1", - "resolved": "https://registry.npm.taobao.org/cacache/download/cacache-13.0.1.tgz?cache=0&sync_timestamp=1594429684526&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcacache%2Fdownload%2Fcacache-13.0.1.tgz", - "integrity": "sha1-qAAMIWlwiQgvhSh6GuxuOCAkpxw=", - "dev": true, - "requires": { - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "minipass": "^3.0.0", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "p-map": "^3.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^2.7.1", - "ssri": "^7.0.0", - "unique-filename": "^1.1.1" - } - }, - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-3.3.1.tgz", - "integrity": "sha1-ibM/rUpGcNqpT4Vff74x1thP6IA=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-4.1.0.tgz", - "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/fs-minipass/download/fs-minipass-2.1.0.tgz", - "integrity": "sha1-f1A2/b8SxjwWkZDL5BmchSJx+fs=", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "jest-worker": { - "version": "25.5.0", - "resolved": "https://registry.npm.taobao.org/jest-worker/download/jest-worker-25.5.0.tgz", - "integrity": "sha1-JhHQcbec6g9D7lej0RhZOsFUfbE=", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz", - "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-3.1.0.tgz?cache=0&sync_timestamp=1587567693680&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmake-dir%2Fdownload%2Fmake-dir-3.1.0.tgz", - "integrity": "sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8=", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-4.1.0.tgz", - "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz", - "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npm.taobao.org/pkg-dir/download/pkg-dir-4.2.0.tgz", - "integrity": "sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM=", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - }, - "ssri": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/ssri/download/ssri-7.1.0.tgz", - "integrity": "sha1-ksJBv23oI2W1x/tL126XVSLhKU0=", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1", - "minipass": "^3.1.1" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.1.0.tgz?cache=0&sync_timestamp=1569557271992&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.1.0.tgz", - "integrity": "sha1-aOMlkd9z4lrRxLSRCKLsUHliv9E=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npm.taobao.org/test-exclude/download/test-exclude-5.2.3.tgz", - "integrity": "sha1-w9Ph4xHrfuQF4JLawQrv0JCR6sA=", - "dev": true, - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - }, - "dependencies": { - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/load-json-file/download/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/read-pkg/download/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/read-pkg-up/download/read-pkg-up-4.0.0.tgz", - "integrity": "sha1-GyIcYIi6d5lgHICPkRYcZuWPiXg=", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/text-table/download/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npm.taobao.org/thenify/download/thenify-3.3.1.tgz?cache=0&sync_timestamp=1592413627028&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fthenify%2Fdownload%2Fthenify-3.3.1.tgz", - "integrity": "sha1-iTLmhqQGYDigFt2eLKRq3Zg4qV8=", - "dev": true, - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npm.taobao.org/thenify-all/download/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", - "dev": true, - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "thread-loader": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/thread-loader/download/thread-loader-2.1.3.tgz", - "integrity": "sha1-y9LBOfwrLebp0o9iKGq3cMGsvdo=", - "dev": true, - "requires": { - "loader-runner": "^2.3.1", - "loader-utils": "^1.1.0", - "neo-async": "^2.6.0" - } - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/throat/download/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", - "dev": true - }, - "throttle-debounce": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/throttle-debounce/download/throttle-debounce-1.1.0.tgz?cache=0&sync_timestamp=1591627280081&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fthrottle-debounce%2Fdownload%2Fthrottle-debounce-1.1.0.tgz", - "integrity": "sha1-UYU9o3vmihVctugns1FKPEIuic0=" - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npm.taobao.org/through2/download/through2-2.0.5.tgz?cache=0&sync_timestamp=1593478693312&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fthrough2%2Fdownload%2Fthrough2-2.0.5.tgz", - "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/thunky/download/thunky-1.1.0.tgz", - "integrity": "sha1-Wrr3FKlAXbBQRzK7zNLO3Z75U30=", - "dev": true - }, - "timers-browserify": { - "version": "2.0.11", - "resolved": "https://registry.npm.taobao.org/timers-browserify/download/timers-browserify-2.0.11.tgz", - "integrity": "sha1-gAsfPu4nLlvFPuRloE0OgEwxIR8=", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/tmpl/download/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz?cache=0&sync_timestamp=1580550317222&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fto-fast-properties%2Fdownload%2Fto-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/to-object-path/download/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/to-regex/download/to-regex-3.0.2.tgz", - "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/extend-shallow/download/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-extendable/download/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz", - "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=", - "dev": true - }, - "toposort": { - "version": "1.0.7", - "resolved": "https://registry.npm.taobao.org/toposort/download/toposort-1.0.7.tgz", - "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", - "dev": true - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.5.0.tgz", - "integrity": "sha1-zZ+yoKodWhK0c72fuW+j3P9lreI=", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/tr46/download/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/trim-newlines/download/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, - "true-case-path": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/true-case-path/download/true-case-path-1.0.3.tgz", - "integrity": "sha1-+BO1qMhrQNpZYGcisUTjIleZ9H0=", - "dev": true, - "requires": { - "glob": "^7.1.2" - } - }, - "tryer": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/tryer/download/tryer-1.0.1.tgz", - "integrity": "sha1-8shUBoALmw90yfdGW4HqrSQSUvg=", - "dev": true - }, - "ts-jest": { - "version": "24.3.0", - "resolved": "https://registry.npm.taobao.org/ts-jest/download/ts-jest-24.3.0.tgz?cache=0&sync_timestamp=1594961073619&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fts-jest%2Fdownload%2Fts-jest-24.3.0.tgz", - "integrity": "sha1-uXgU4+qzWeqEChrBEt6uaKpECGk=", - "dev": true, - "requires": { - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "json5": "2.x", - "lodash.memoize": "4.x", - "make-error": "1.x", - "mkdirp": "0.x", - "resolve": "1.x", - "semver": "^5.5", - "yargs-parser": "10.x" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/json5/download/json5-2.1.3.tgz", - "integrity": "sha1-ybD3+pIzv+WAf+ZvzzpWF+1ZfUM=", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-10.1.0.tgz?cache=0&sync_timestamp=1595125126126&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-10.1.0.tgz", - "integrity": "sha1-cgImW4n36eny5XZeD+c1qQXtuqg=", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, - "ts-pnp": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/ts-pnp/download/ts-pnp-1.2.0.tgz", - "integrity": "sha1-pQCtCEsHmPHDBxrzkeZZEshrypI=", - "dev": true - }, - "tsconfig": { - "version": "7.0.0", - "resolved": "https://registry.npm.taobao.org/tsconfig/download/tsconfig-7.0.0.tgz", - "integrity": "sha1-hFOIdaTcIW5cSlQys6Tew9VOkbc=", - "dev": true, - "requires": { - "@types/strip-bom": "^3.0.0", - "@types/strip-json-comments": "0.0.30", - "strip-bom": "^3.0.0", - "strip-json-comments": "^2.0.0" - } - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-1.13.0.tgz", - "integrity": "sha1-yIHhPMcBWJTtkUhi0nZDb6mkcEM=", - "dev": true - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npm.taobao.org/tty-browserify/download/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz?cache=0&sync_timestamp=1581364203962&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftweetnacl%2Fdownload%2Ftweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npm.taobao.org/type-check/download/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npm.taobao.org/type-is/download/type-is-1.6.18.tgz", - "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npm.taobao.org/uglify-js/download/uglify-js-3.4.10.tgz?cache=0&sync_timestamp=1592744803278&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuglify-js%2Fdownload%2Fuglify-js-3.4.10.tgz", - "integrity": "sha1-mtlWPY6zrN+404WX0q8dgV9qdV8=", - "dev": true, - "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.19.0.tgz?cache=0&sync_timestamp=1592632050401&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.19.0.tgz", - "integrity": "sha1-9hmKqE5bg8RgVLlN3tv+1e6f8So=", - "dev": true - } - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/unicode-canonical-property-names-ecmascript/download/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha1-JhmADEyCWADv3YNDr33Zkzy+KBg=", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/unicode-match-property-ecmascript/download/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha1-jtKjJWmWG86SJ9Cc0/+7j+1fAgw=", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/unicode-match-property-value-ecmascript/download/unicode-match-property-value-ecmascript-1.2.0.tgz?cache=0&sync_timestamp=1583948752590&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funicode-match-property-value-ecmascript%2Fdownload%2Funicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha1-DZH2AO7rMJaqlisdb8iIduZOpTE=", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/unicode-property-aliases-ecmascript/download/unicode-property-aliases-ecmascript-1.1.0.tgz?cache=0&sync_timestamp=1583945797274&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funicode-property-aliases-ecmascript%2Fdownload%2Funicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha1-3Vepn2IHvt/0Yoq++5TFDblByPQ=", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/union-value/download/union-value-1.0.1.tgz", - "integrity": "sha1-C2/nuDWuzaYcbqTU8CwUIh4QmEc=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/uniq/download/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/uniqs/download/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", - "dev": true - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/unique-filename/download/unique-filename-1.1.1.tgz", - "integrity": "sha1-HWl2k2mtoFgxA6HmrodoG1ZXMjA=", - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/unique-slug/download/unique-slug-2.0.2.tgz", - "integrity": "sha1-uqvOkQg/xk6UWw861hPiZPfNTmw=", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz?cache=0&sync_timestamp=1583530825899&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funiversalify%2Fdownload%2Funiversalify-0.1.2.tgz", - "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/unquote/download/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/unset-value/download/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npm.taobao.org/has-value/download/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/isobject/download/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/has-values/download/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/upath/download/upath-1.2.0.tgz", - "integrity": "sha1-j2bbzVWog6za5ECK+LA1pQRMGJQ=", - "dev": true - }, - "upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/upper-case/download/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", - "dev": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npm.taobao.org/uri-js/download/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npm.taobao.org/urix/download/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npm.taobao.org/url/download/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, - "url-loader": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/url-loader/download/url-loader-2.3.0.tgz", - "integrity": "sha1-4OLvZY8APvuMpBsPP/v3a6uIZYs=", - "dev": true, - "requires": { - "loader-utils": "^1.2.3", - "mime": "^2.4.4", - "schema-utils": "^2.5.0" - } - }, - "url-parse": { - "version": "1.4.7", - "resolved": "https://registry.npm.taobao.org/url-parse/download/url-parse-1.4.7.tgz", - "integrity": "sha1-qKg1NejACjFuQDpdtKwbm4U64ng=", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/use/download/use-3.1.1.tgz", - "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=", - "dev": true - }, - "util": { - "version": "0.10.4", - "resolved": "https://registry.npm.taobao.org/util/download/util-0.10.4.tgz?cache=0&sync_timestamp=1588238331562&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Futil%2Fdownload%2Futil-0.10.4.tgz", - "integrity": "sha1-OqASW/5mikZy3liFfTrOJ+y3aQE=", - "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.1.tgz", - "integrity": "sha1-a693dLgO6w91INi4HQeYKlmruu4=", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/utila/download/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/uuid/download/uuid-3.4.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuuid%2Fdownload%2Fuuid-3.4.0.tgz", - "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", - "dev": true - }, - "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/v8-compile-cache/download/v8-compile-cache-2.1.1.tgz", - "integrity": "sha1-VLw83UMxe8qR413K8wWxpyN950U=", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npm.taobao.org/validate-npm-package-license/download/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "vcrontab": { - "version": "0.3.5", - "resolved": "https://registry.npm.taobao.org/vcrontab/download/vcrontab-0.3.5.tgz", - "integrity": "sha1-dXH9UFoMskMu5FgfHcofA65gbLs=", - "requires": { - "element-ui": "^2.4.11", - "vue": "^2.5.17" - }, - "dependencies": { - "element-ui": { - "version": "2.13.2", - "resolved": "https://registry.npm.taobao.org/element-ui/download/element-ui-2.13.2.tgz?cache=0&sync_timestamp=1589795216634&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Felement-ui%2Fdownload%2Felement-ui-2.13.2.tgz", - "integrity": "sha1-WCv0eqqqr+I+oZWPriF6aHrQZEc=", - "requires": { - "async-validator": "~1.8.1", - "babel-helper-vue-jsx-merge-props": "^2.0.0", - "deepmerge": "^1.2.0", - "normalize-wheel": "^1.0.1", - "resize-observer-polyfill": "^1.5.0", - "throttle-debounce": "^1.0.1" - } - }, - "vue": { - "version": "2.6.11", - "resolved": "https://registry.npm.taobao.org/vue/download/vue-2.6.11.tgz", - "integrity": "sha1-dllNh31LEiNEBuhONSdcbVFBJcU=" - } - } - }, - "vendors": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/vendors/download/vendors-1.0.4.tgz?cache=0&sync_timestamp=1579857147055&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvendors%2Fdownload%2Fvendors-1.0.4.tgz", - "integrity": "sha1-4rgApT56Kbk1BsPPQRANFsTErY4=", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/vm-browserify/download/vm-browserify-1.1.2.tgz?cache=0&sync_timestamp=1572870717730&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvm-browserify%2Fdownload%2Fvm-browserify-1.1.2.tgz", - "integrity": "sha1-eGQcSIuObKkadfUR56OzKobl3aA=", - "dev": true - }, - "vue": { - "version": "2.6.11", - "resolved": "https://registry.npm.taobao.org/vue/download/vue-2.6.11.tgz", - "integrity": "sha1-dllNh31LEiNEBuhONSdcbVFBJcU=" - }, - "vue-ba": { - "version": "1.2.8", - "resolved": "https://registry.npm.taobao.org/vue-ba/download/vue-ba-1.2.8.tgz", - "integrity": "sha1-rINh6Iv+/Tkrd72b1bhqPZl0Yn8=", - "requires": { - "deep-equal": "^1.0.1", - "vue": "^2.3.3" - }, - "dependencies": { - "vue": { - "version": "2.6.11", - "resolved": "https://registry.npm.taobao.org/vue/download/vue-2.6.11.tgz", - "integrity": "sha1-dllNh31LEiNEBuhONSdcbVFBJcU=" - } - } - }, - "vue-codemirror": { - "version": "4.0.6", - "resolved": "https://registry.npm.taobao.org/vue-codemirror/download/vue-codemirror-4.0.6.tgz", - "integrity": "sha1-t4a7gNjXYqk6q45G95qBAG8EN8Q=", - "requires": { - "codemirror": "^5.41.0", - "diff-match-patch": "^1.0.0" - } - }, - "vue-codemirror-lite": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/vue-codemirror-lite/download/vue-codemirror-lite-1.0.4.tgz", - "integrity": "sha1-SKXNfRfAkUUDyM2dm1a0OOScNBA=", - "requires": { - "codemirror": "^5.22.0" - } - }, - "vue-eslint-parser": { - "version": "7.1.0", - "resolved": "https://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-7.1.0.tgz?cache=0&sync_timestamp=1589539351926&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-eslint-parser%2Fdownload%2Fvue-eslint-parser-7.1.0.tgz", - "integrity": "sha1-nNvMgj5lawh1B6GRFzK4Z6wQHoM=", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-scope": "^5.0.0", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.2.1", - "esquery": "^1.0.1", - "lodash": "^4.17.15" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "vue-github-button": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/vue-github-button/download/vue-github-button-1.2.0.tgz", - "integrity": "sha1-ViSigHsWvaxhWJ9VUDuKSS0qnVs=", - "requires": { - "github-buttons": "^2.8.0" - } - }, - "vue-hot-reload-api": { - "version": "2.3.4", - "resolved": "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.4.tgz", - "integrity": "sha1-UylVzB6yCKPZkLOp+acFdGV+CPI=", - "dev": true - }, - "vue-i18n": { - "version": "8.18.2", - "resolved": "https://registry.npm.taobao.org/vue-i18n/download/vue-i18n-8.18.2.tgz", - "integrity": "sha1-zXwS8uF45vqiOw48/S97rJMF+Pw=" - }, - "vue-jest": { - "version": "3.0.5", - "resolved": "https://registry.npm.taobao.org/vue-jest/download/vue-jest-3.0.5.tgz", - "integrity": "sha1-1vEktULcv/IHv5KWwZQT9MQLcMk=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", - "chalk": "^2.1.0", - "extract-from-css": "^0.4.4", - "find-babel-config": "^1.1.0", - "js-beautify": "^1.6.14", - "node-cache": "^4.1.1", - "object-assign": "^4.1.1", - "source-map": "^0.5.6", - "tsconfig": "^7.0.0", - "vue-template-es2015-compiler": "^1.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "vue-loader": { - "version": "15.9.2", - "resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-15.9.2.tgz", - "integrity": "sha1-rgH19MnGoEv/RIORLnLvkaQCwa4=", - "dev": true, - "requires": { - "@vue/component-compiler-utils": "^3.1.0", - "hash-sum": "^1.0.2", - "loader-utils": "^1.1.0", - "vue-hot-reload-api": "^2.3.0", - "vue-style-loader": "^4.1.0" - }, - "dependencies": { - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", - "dev": true - } - } - }, - "vue-router": { - "version": "3.3.4", - "resolved": "https://registry.npm.taobao.org/vue-router/download/vue-router-3.3.4.tgz?cache=0&sync_timestamp=1594111718735&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-router%2Fdownload%2Fvue-router-3.3.4.tgz", - "integrity": "sha1-Tjirw0oRxBtsPYJERJouNjumJQs=" - }, - "vue-style-loader": { - "version": "4.1.2", - "resolved": "https://registry.npm.taobao.org/vue-style-loader/download/vue-style-loader-4.1.2.tgz", - "integrity": "sha1-3t80mAbyXOtOZPOtfApE+6c1/Pg=", - "dev": true, - "requires": { - "hash-sum": "^1.0.2", - "loader-utils": "^1.0.2" - }, - "dependencies": { - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", - "dev": true - } - } - }, - "vue-template-compiler": { - "version": "2.6.11", - "resolved": "https://registry.npm.taobao.org/vue-template-compiler/download/vue-template-compiler-2.6.11.tgz", - "integrity": "sha1-wEcE749JixUxMAGJk+VjCdRpgIA=", - "dev": true, - "requires": { - "de-indent": "^1.0.2", - "he": "^1.1.0" - } - }, - "vue-template-es2015-compiler": { - "version": "1.9.1", - "resolved": "https://registry.npm.taobao.org/vue-template-es2015-compiler/download/vue-template-es2015-compiler-1.9.1.tgz", - "integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=", - "dev": true - }, - "vue-tour": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/vue-tour/download/vue-tour-1.4.0.tgz", - "integrity": "sha1-6O8GVumPh+VWWfAMPdZOxYU5RbE=", - "requires": { - "hash-sum": "^2.0.0", - "jump.js": "^1.0.2", - "popper.js": "^1.16.0", - "vue": "^2.6.10" - }, - "dependencies": { - "hash-sum": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-2.0.0.tgz", - "integrity": "sha1-gdAbtd6OpKIUrV1urRtSNGCwtFo=" - }, - "vue": { - "version": "2.6.11", - "resolved": "https://registry.npm.taobao.org/vue/download/vue-2.6.11.tgz", - "integrity": "sha1-dllNh31LEiNEBuhONSdcbVFBJcU=" - } - } - }, - "vue-virtual-scroll-list": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/vue-virtual-scroll-list/download/vue-virtual-scroll-list-2.3.0.tgz?cache=0&sync_timestamp=1592531729489&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-virtual-scroll-list%2Fdownload%2Fvue-virtual-scroll-list-2.3.0.tgz", - "integrity": "sha1-1d2mC0iQrO9nDtHUQStgxxN7twY=" - }, - "vuex": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/vuex/download/vuex-3.4.0.tgz", - "integrity": "sha1-IMwIYGLXUHafzh/rs05/zurr3kU=" - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/w3c-hr-time/download/w3c-hr-time-1.0.2.tgz", - "integrity": "sha1-ConN9cwVgi35w2BUNnaWPgzDCM0=", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/w3c-xmlserializer/download/w3c-xmlserializer-1.1.2.tgz", - "integrity": "sha1-MEhcp9cKb9BSQgo9Ev2Q5jOc55Q=", - "dev": true, - "requires": { - "domexception": "^1.0.1", - "webidl-conversions": "^4.0.2", - "xml-name-validator": "^3.0.0" - } - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npm.taobao.org/walker/download/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.x" - } - }, - "watchpack": { - "version": "1.7.2", - "resolved": "https://registry.npm.taobao.org/watchpack/download/watchpack-1.7.2.tgz?cache=0&sync_timestamp=1589640789951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwatchpack%2Fdownload%2Fwatchpack-1.7.2.tgz", - "integrity": "sha1-wC5NTUmRPD5+EiwzJTZa+dMx6ao=", - "dev": true, - "requires": { - "chokidar": "^3.4.0", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.0" - }, - "dependencies": { - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.1.tgz?cache=0&sync_timestamp=1569897341237&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fanymatch%2Fdownload%2Fanymatch-3.1.1.tgz", - "integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=", - "dev": true, - "optional": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.1.0.tgz?cache=0&sync_timestamp=1593261627308&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbinary-extensions%2Fdownload%2Fbinary-extensions-2.1.0.tgz", - "integrity": "sha1-MPpAyef+B9vIlWeM0ocCTeokHdk=", - "dev": true, - "optional": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz", - "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", - "dev": true, - "optional": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "chokidar": { - "version": "3.4.1", - "resolved": "https://registry.npm.taobao.org/chokidar/download/chokidar-3.4.1.tgz?cache=0&sync_timestamp=1594864807174&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchokidar%2Fdownload%2Fchokidar-3.4.1.tgz", - "integrity": "sha1-6QW97PEOqgoLHbDGZEgcxMvCK6E=", - "dev": true, - "optional": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.4.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz", - "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", - "dev": true, - "optional": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.1.3.tgz", - "integrity": "sha1-+3OHA66NL5/pAMM4Nt3r7ouX8j4=", - "dev": true, - "optional": true - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-5.1.1.tgz", - "integrity": "sha1-tsHvQXxOVmPqSY8cRa+saRa7wik=", - "dev": true, - "optional": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz", - "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz", - "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", - "dev": true, - "optional": true - }, - "readdirp": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-3.4.0.tgz", - "integrity": "sha1-n9zN+ekVWAVEkiGsZF6DA6tbmto=", - "dev": true, - "optional": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz", - "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", - "dev": true, - "optional": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "watchpack-chokidar2": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/watchpack-chokidar2/download/watchpack-chokidar2-2.0.0.tgz?cache=0&sync_timestamp=1589640772386&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwatchpack-chokidar2%2Fdownload%2Fwatchpack-chokidar2-2.0.0.tgz", - "integrity": "sha1-mUihhmy71suCTeoTp+1pH2yN3/A=", - "dev": true, - "optional": true, - "requires": { - "chokidar": "^2.1.8" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npm.taobao.org/wbuf/download/wbuf-1.7.3.tgz", - "integrity": "sha1-wdjRSTFtPqhShIiVy2oL/oh7h98=", - "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/wcwidth/download/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/webidl-conversions/download/webidl-conversions-4.0.2.tgz", - "integrity": "sha1-qFWYCx8LazWbodXZ+zmulB+qY60=", - "dev": true - }, - "webpack": { - "version": "4.43.0", - "resolved": "https://registry.npm.taobao.org/webpack/download/webpack-4.43.0.tgz?cache=0&sync_timestamp=1594294511041&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack%2Fdownload%2Fwebpack-4.43.0.tgz", - "integrity": "sha1-xIVHsR1WMiTFYdrRFyyKoLimeOY=", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/wasm-edit": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.6.1", - "webpack-sources": "^1.4.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-6.4.1.tgz?cache=0&sync_timestamp=1591869461226&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-6.4.1.tgz", - "integrity": "sha1-Ux5Yuj9RudrLmmZGyk3r9bFMpHQ=", - "dev": true - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npm.taobao.org/eslint-scope/download/eslint-scope-4.0.3.tgz", - "integrity": "sha1-ygODMxD2iJoyZHgaqC5j65z+eEg=", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "terser-webpack-plugin": { - "version": "1.4.4", - "resolved": "https://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-1.4.4.tgz?cache=0&sync_timestamp=1594912432309&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser-webpack-plugin%2Fdownload%2Fterser-webpack-plugin-1.4.4.tgz", - "integrity": "sha1-LGNUQ0cyS6r6mla6rd8WNMir/C8=", - "dev": true, - "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^3.1.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - } - } - } - }, - "webpack-bundle-analyzer": { - "version": "3.8.0", - "resolved": "https://registry.npm.taobao.org/webpack-bundle-analyzer/download/webpack-bundle-analyzer-3.8.0.tgz", - "integrity": "sha1-zms/kI2vBp/R9yZvaSy7O97ZuhY=", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1", - "bfj": "^6.1.1", - "chalk": "^2.4.1", - "commander": "^2.18.0", - "ejs": "^2.6.1", - "express": "^4.16.3", - "filesize": "^3.6.1", - "gzip-size": "^5.0.0", - "lodash": "^4.17.15", - "mkdirp": "^0.5.1", - "opener": "^1.5.1", - "ws": "^6.0.0" - } - }, - "webpack-chain": { - "version": "6.4.0", - "resolved": "https://registry.npm.taobao.org/webpack-chain/download/webpack-chain-6.4.0.tgz", - "integrity": "sha1-IvCye2qbye48uk+eZRPPZjlANOI=", - "dev": true, - "requires": { - "deepmerge": "^1.5.2", - "javascript-stringify": "^2.0.1" - } - }, - "webpack-dev-middleware": { - "version": "3.7.2", - "resolved": "https://registry.npm.taobao.org/webpack-dev-middleware/download/webpack-dev-middleware-3.7.2.tgz?cache=0&sync_timestamp=1594744455919&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-dev-middleware%2Fdownload%2Fwebpack-dev-middleware-3.7.2.tgz", - "integrity": "sha1-ABnD23FuP6XOy/ZPKriKdLqzMfM=", - "dev": true, - "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", - "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" - } - }, - "webpack-dev-server": { - "version": "3.11.0", - "resolved": "https://registry.npm.taobao.org/webpack-dev-server/download/webpack-dev-server-3.11.0.tgz?cache=0&sync_timestamp=1588951596228&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-dev-server%2Fdownload%2Fwebpack-dev-server-3.11.0.tgz", - "integrity": "sha1-jxVKO84bz9HMYY705wMniFXn/4w=", - "dev": true, - "requires": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.8", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", - "express": "^4.17.1", - "html-entities": "^1.3.1", - "http-proxy-middleware": "0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.3", - "killable": "^1.0.1", - "loglevel": "^1.6.8", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.26", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.7", - "semver": "^6.3.0", - "serve-index": "^1.9.1", - "sockjs": "0.3.20", - "sockjs-client": "1.4.0", - "spdy": "^4.0.2", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.2", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "^13.3.2" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "is-absolute-url": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/is-absolute-url/download/is-absolute-url-3.0.3.tgz?cache=0&sync_timestamp=1569735515256&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-absolute-url%2Fdownload%2Fis-absolute-url-3.0.3.tgz", - "integrity": "sha1-lsaiK2ojkpsR6gr7GDbDatSl1pg=", - "dev": true - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz", - "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586886301819&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280549549&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "webpack-log": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/webpack-log/download/webpack-log-2.0.0.tgz", - "integrity": "sha1-W3ko4GN1k/EZ0y9iJ8HgrDHhtH8=", - "dev": true, - "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - } - }, - "webpack-merge": { - "version": "4.2.2", - "resolved": "https://registry.npm.taobao.org/webpack-merge/download/webpack-merge-4.2.2.tgz?cache=0&sync_timestamp=1594294979021&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-merge%2Fdownload%2Fwebpack-merge-4.2.2.tgz", - "integrity": "sha1-onxS6ng9E5iv0gh/VH17nS9DY00=", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npm.taobao.org/webpack-sources/download/webpack-sources-1.4.3.tgz", - "integrity": "sha1-7t2OwLko+/HL/plOItLYkPMwqTM=", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "websocket-driver": { - "version": "0.6.5", - "resolved": "https://registry.npm.taobao.org/websocket-driver/download/websocket-driver-0.6.5.tgz?cache=0&sync_timestamp=1591288882525&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebsocket-driver%2Fdownload%2Fwebsocket-driver-0.6.5.tgz", - "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", - "dev": true, - "requires": { - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/websocket-extensions/download/websocket-extensions-0.1.4.tgz", - "integrity": "sha1-f4RzvIOd/YdgituV1+sHUhFXikI=", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/whatwg-encoding/download/whatwg-encoding-1.0.5.tgz", - "integrity": "sha1-WrrPd3wyFmpR0IXWtPPn0nET3bA=", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/whatwg-mimetype/download/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha1-PUseAxLSB5h5+Cav8Y2+7KWWD78=", - "dev": true - }, - "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npm.taobao.org/whatwg-url/download/whatwg-url-6.5.0.tgz", - "integrity": "sha1-8t8Cv/F2/WUHDfdK1cy7WhmZZag=", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npm.taobao.org/which/download/which-1.3.1.tgz", - "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/wide-align/download/wide-align-1.1.3.tgz", - "integrity": "sha1-rgdOa9wMFKQx6ATmJFScYzsABFc=", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz", - "integrity": "sha1-YQY29rH3A4kb00dxzLF/uTtHB5w=", - "dev": true - }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npm.taobao.org/worker-farm/download/worker-farm-1.7.0.tgz", - "integrity": "sha1-JqlMU5G7ypJhUgAvabhKS/dy5ag=", - "dev": true, - "requires": { - "errno": "~0.1.7" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-5.1.0.tgz", - "integrity": "sha1-H9H2cjXVttD+54EFYAG/tpTAOwk=", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/write/download/write-1.0.3.tgz?cache=0&sync_timestamp=1567579932525&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwrite%2Fdownload%2Fwrite-1.0.3.tgz", - "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "ws": { - "version": "6.2.1", - "resolved": "https://registry.npm.taobao.org/ws/download/ws-6.2.1.tgz?cache=0&sync_timestamp=1593925423349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fws%2Fdownload%2Fws-6.2.1.tgz", - "integrity": "sha1-RC/fCkftZPWbal2P8TD0dI7VJPs=", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/xml-name-validator/download/xml-name-validator-3.0.0.tgz", - "integrity": "sha1-auc+Bt5NjG5H+fsYH3jWSK1FfGo=", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npm.taobao.org/xmlchars/download/xmlchars-2.2.0.tgz", - "integrity": "sha1-Bg/hvLf5x2/ioX24apvDq4lCEMs=", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz", - "integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/y18n/download/y18n-4.0.0.tgz", - "integrity": "sha1-le+U+F7MgdAHwmThkKEg8KPIVms=" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-3.1.1.tgz", - "integrity": "sha1-27fa+b/YusmrRev2ArjLrQ1dCP0=", - "dev": true - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npm.taobao.org/yargs/download/yargs-13.3.2.tgz?cache=0&sync_timestamp=1594421142336&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-13.3.2.tgz", - "integrity": "sha1-rX/+/sGqWVZayRX4Lcyzipwxot0=", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-13.1.2.tgz?cache=0&sync_timestamp=1595125126126&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-13.1.2.tgz", - "integrity": "sha1-Ew8JcC667vJlDVTObj5XBvek+zg=", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yorkie": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/yorkie/download/yorkie-2.0.0.tgz", - "integrity": "sha1-kkEZEtQ1IU4SxRwq4Qk+VLa7g9k=", - "dev": true, - "requires": { - "execa": "^0.8.0", - "is-ci": "^1.0.10", - "normalize-path": "^1.0.0", - "strip-indent": "^2.0.0" - }, - "dependencies": { - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npm.taobao.org/ci-info/download/ci-info-1.6.0.tgz", - "integrity": "sha1-LKINu5zrMtRSSmgzAzE/AwSx5Jc=", - "dev": true - }, - "execa": { - "version": "0.8.0", - "resolved": "https://registry.npm.taobao.org/execa/download/execa-0.8.0.tgz?cache=0&sync_timestamp=1594145085955&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexeca%2Fdownload%2Fexeca-0.8.0.tgz", - "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/get-stream/download/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npm.taobao.org/is-ci/download/is-ci-1.2.1.tgz", - "integrity": "sha1-43ecjuF/zPQoSI9uKBGH8uYyhBw=", - "dev": true, - "requires": { - "ci-info": "^1.5.0" - } - }, - "normalize-path": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-1.0.0.tgz", - "integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k=", - "dev": true - } - } - }, - "zrender": { - "version": "4.3.1", - "resolved": "https://registry.npm.taobao.org/zrender/download/zrender-4.3.1.tgz", - "integrity": "sha1-uviqbcgYei+BlpLX1fm+36K5D6M=" - } - } -} diff --git a/frontend/package.json b/frontend/package.json index 8e02d5fe..70ee63a8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,67 +1,67 @@ { - "name": "crawlab", - "version": "0.4.10", - "private": true, + "name": "crawlab-frontend", + "version": "0.1.0", + "private": false, "scripts": { - "serve": "vue-cli-service serve --ip=0.0.0.0 --mode=development", - "test:unit": "vue-cli-service test:unit", + "serve": "vue-cli-service serve --port=8081", + "build": "vue-cli-service build", "lint": "vue-cli-service lint", - "build:dev": "vue-cli-service build --mode development", - "build:prod": "vue-cli-service build --mode production", - "config": "vue ui", - "serve:prod": "vue-cli-service serve --mode=production --ip=0.0.0.0" + "test": "jest" }, "dependencies": { - "@fortawesome/fontawesome-svg-core": "^1.2.28", - "@fortawesome/free-brands-svg-icons": "^5.13.0", - "@fortawesome/free-regular-svg-icons": "^5.13.0", - "@fortawesome/free-solid-svg-icons": "^5.13.0", - "@fortawesome/vue-fontawesome": "^0.1.9", - "@tinymce/tinymce-vue": "^3.2.2", - "ansi-to-html": "^0.6.14", - "axios": "^0.19.2", - "babel-polyfill": "^6.26.0", + "@fortawesome/fontawesome-svg-core": "^1.2.32", + "@fortawesome/free-brands-svg-icons": "^5.15.1", + "@fortawesome/free-regular-svg-icons": "^5.15.1", + "@fortawesome/free-solid-svg-icons": "^5.15.1", + "@fortawesome/vue-fontawesome": "^3.0.0-2", + "@popperjs/core": "^2.6.0", + "@types/codemirror": "^0.0.103", + "@types/echarts": "^4.9.8", + "@types/humanize-duration": "^3.25.0", + "@types/javascript-time-ago": "^2.0.2", + "@types/md5": "^2.2.1", + "@types/pinyin": "^2.8.2", + "atom-material-icons": "^3.0.0", + "axios": "^0.21.1", + "codemirror": "^5.59.1", "core-js": "^3.6.5", - "cross-env": "^7.0.2", - "dayjs": "^1.8.28", - "echarts": "^4.8.0", - "element-ui": "^2.13.2", + "cron-parser": "^3.5.0", + "cronstrue": "^1.114.0", + "dayjs": "^1.10.5", + "echarts": "^5.1.2", + "element-plus": "1.0.2-beta.40", "font-awesome": "^4.7.0", - "github-markdown-css": "^4.0.0", - "js-cookie": "^2.2.1", + "humanize-duration": "^3.26.0", + "javascript-time-ago": "^2.3.6", + "md5": "^2.3.0", + "node-sass": "^5.0.0", "normalize.css": "^8.0.1", - "npm": "^6.14.5", - "nprogress": "^0.2.0", - "path": "^0.12.7", - "showdown": "^1.9.1", - "vcrontab": "^0.3.5", - "vue": "^2.6.11", - "vue-ba": "^1.2.8", - "vue-codemirror": "^4.0.6", - "vue-codemirror-lite": "^1.0.4", - "vue-github-button": "^1.2.0", - "vue-i18n": "^8.18.1", - "vue-router": "^3.3.2", - "vue-tour": "^1.4.0", - "vue-virtual-scroll-list": "^2.2.6", - "vuex": "^3.4.0" + "pinyin": "^2.10.2", + "point-cluster": "^3.1.8", + "vue": "^3.0.4", + "vue-clipboard3": "^1.0.1", + "vue-i18n": "^9.0.0-beta.11", + "vue-router": "^4.0.0-0", + "vue3-dropzone": "^0.0.7", + "vuex": "^4.0.0-0" }, "devDependencies": { - "@babel/core": "^7.10.2", - "@babel/register": "^7.10.1", - "@vue/cli-plugin-babel": "~4.4.0", - "@vue/cli-plugin-eslint": "^4.4.1", - "@vue/cli-plugin-unit-jest": "~4.4.0", - "@vue/cli-service": "^4.4.1", - "@vue/test-utils": "^1.0.3", - "autoprefixer": "^9.5.1", - "babel-core": "^7.0.0-bridge.0", - "babel-eslint": "^10.1.0", - "babel-jest": "^26.0.1", - "eslint": "^6.8.0", - "eslint-plugin-vue": "^6.2.2", - "node-sass": "^4.14.1", - "sass-loader": "^8.0.2", - "vue-template-compiler": "^2.6.11" + "@babel/preset-typescript": "^7.12.7", + "@types/jest": "^26.0.19", + "@typescript-eslint/eslint-plugin": "^2.33.0", + "@typescript-eslint/parser": "^2.33.0", + "@vue/cli-plugin-babel": "~4.5.0", + "@vue/cli-plugin-eslint": "~4.5.0", + "@vue/cli-plugin-router": "~4.5.0", + "@vue/cli-plugin-typescript": "~4.5.0", + "@vue/cli-plugin-vuex": "~4.5.0", + "@vue/cli-service": "~4.5.0", + "@vue/compiler-sfc": "^3.0.0", + "@vue/eslint-config-typescript": "^5.0.2", + "eslint": "^6.7.2", + "eslint-plugin-vue": "^7.0.0-0", + "sass-loader": "^10.1.0", + "scss-loader": "^0.0.1", + "typescript": "~3.9.3" } } diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js deleted file mode 100644 index 961986e2..00000000 --- a/frontend/postcss.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - plugins: { - autoprefixer: {} - } -} diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico index 3fb253bdbf7a46c65a6880838d3b0fd1ecb20701..df36fcfb72584e00488330b560ebcf34a41c64c2 100644 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 16958 zcmd^GU1%Le6yCI8d?;=4L42yA_|RvOy!N6X2!beBL;N9%D2k#eNUTs3G$<57DJp_m zS`5{OriRAGQcJEsMJrZ~SmO^h38JyB(MY8=8a;mB?wxk`-rb$qv%8mEGvQ?Jot<;$ zd}q$goSC`nd2RTsR6P9e@HSlOc^7-0w*iDAuMfm>KUIRPng8Y0$~sUtXaKYqbPO~L z`W^Iljrf^me8xJgOP+Pj)U}AVptA?6fL;Mjfg~r*)MQa+5h|7<1G=pO^@5Ir@?uWn zr);*dsuU0kq0nV5XbWf#l%#jju2!gA2n*V#pWgyH0V*1wt30+%9SXtZDg^Cy zfW|?tdX`;}x~zBAKTkch!+DwWb=jD*%BN1s-PmFXx?YeKXIy>C0gbf~c4GtToXZB_r_b+dLF~o`)LlImz`Lz<&YovYtgvF z^3KeO?C#RqfY{b1*#OU;P-CZW7Ul0@ym6oBXG8|C)7qdv4nOSz`b~}h=*w}MmRI)E zXIlKk*x&;w+pNaE?_T%$ec^Pl29EcO4EJDezdoQnw_<&KN@V(dcbmOCptZr~dLIDx zNfrJbSBspUb<_E)VYgUkei-4EF*UZF$4F`al}2MJLYiRLGT?_@p4{EOWfn@bZRCau}`V=w9S1*js0?M zNbI~z%5HO8eD=*~c9|MI^6~Kg=&TCAE$-pEolm!B@DuxjO3(ife%+qew&&qIz4ZH^ zV}DAer)_W2I`f}y{j=@UTVwq@g1%=Aklk0C8UJYXbK@a)#(>%J^Zdq^4m^@wu0|I< z53%d^KfIH$rK0A*!_UOWy(Si}KB=`cvFrE09OG$;`$PRX?RiYLSS!c=w{`|Fp&A1p zzmSGLc&6W*2Ke_sXm5jcvX24({G*0ncmBn`wVeTQA2^1+a(4Yhc*gLH#mCOhYwyLv z=U<&F{fLQizAaJ5H}A}51K0Z${XXMz_Pt5KuRH&y5AaOimUxc&!B#gL@XU<&8!l=1 zb~l+(|BIY|(+0q=zyJ8~Sr<)%I-E0EKki(RKEksM+nKLvO@Fo;cmI*^{>yeAVssAY zoIALWAh}{T{2WudwI%lctL6i`vq1V5&$@U&-HhbVsSj!Vo; zJdTAOEnow_cc=c%x51l~L-uW;{A*+JzE7P>d;cYD546MhU>uY*_L^NzT{^-#mi-y+ zac*3e@4tm@3mcgCA9eR=Iv?V_72khM-OGgaEc-KbSq+K5s92XT3*NPcX z-nn3^CW|ubn_JS~p)Y-cXRBN@20(j3uJ6B-=L%4%@AzWtRbA=tzZN}jBR|Z0-Wujr z&+{M9#Q2KGeuY1oUy9!;GjI2+`4#*4y-kD}82%0N$4&0DLx9f?0VYRlOlzk7%xkaD ztDc`$n!GRg-j#ttSob~1J|xv{JCQ6TJGWsVM- dW{!UF1)yI{Klu#kw{!hy`V|#6vOMVb{{SrgFHryh diff --git a/frontend/public/font-awesome.min.css b/frontend/public/font-awesome.min.css deleted file mode 100644 index 540440ce..00000000 --- a/frontend/public/font-awesome.min.css +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/frontend/public/index.html b/frontend/public/index.html index 3b3ab33b..8f70dc07 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -1,162 +1,17 @@ - - - - - - - - - - - - Crawlab + + + + + <%= htmlWebpackPlugin.options.title %> -
-
-
-

- C - R - A - W - L - A - B -

-
-
- Easy crawling -
-
- Loading... -
-
-
+
diff --git a/frontend/sources.list b/frontend/sources.list deleted file mode 100644 index 6ff85f91..00000000 --- a/frontend/sources.list +++ /dev/null @@ -1,4 +0,0 @@ -deb http://mirrors.aliyun.com/debian/ jessie main non-free contrib -deb http://mirrors.aliyun.com/debian/ jessie-proposed-updates main non-free contrib -deb-src http://mirrors.aliyun.com/debian/ jessie main non-free contrib -deb-src http://mirrors.aliyun.com/debian/ jessie-proposed-updates main non-free contrib diff --git a/frontend/src/App.vue b/frontend/src/App.vue index b6d0d057..083049bd 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,145 +1,3 @@ - - - - diff --git a/frontend/src/api/request.js b/frontend/src/api/request.js deleted file mode 100644 index fa80fe89..00000000 --- a/frontend/src/api/request.js +++ /dev/null @@ -1,31 +0,0 @@ -import service from '@/utils/request' - -const get = (path, params) => { - return service.get(path, { - params - }) -} - -const post = (path, data) => { - return service.post(path, data) -} - -const put = (path, data) => { - return service.put(path, data) -} - -const del = (path, data) => { - return service.delete(path, { - data - }) -} -const request = service.request - -export default { - baseUrl: service.defaults.baseURL, - request, - get, - post, - put, - delete: del -} diff --git a/frontend/src/assets/404_images/404 2.png b/frontend/src/assets/404_images/404 2.png deleted file mode 100644 index 3d8e2305cc973ad2121403aee4bf08728f76c461..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98071 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 diff --git a/frontend/src/assets/404_images/404.png b/frontend/src/assets/404_images/404.png deleted file mode 100644 index 3d8e2305cc973ad2121403aee4bf08728f76c461..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98071 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 diff --git a/frontend/src/assets/404_images/404_cloud.png b/frontend/src/assets/404_images/404_cloud.png deleted file mode 100644 index c6281d09013e0a2c5f8e699a0a6038d9480291e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4766 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 diff --git a/frontend/src/assets/js/loginCanvas.js b/frontend/src/assets/js/loginCanvas.js new file mode 100644 index 00000000..705e5f9a --- /dev/null +++ b/frontend/src/assets/js/loginCanvas.js @@ -0,0 +1,262 @@ +function initCanvas() { + let canvas, ctx, circ, nodes, mouse, SENSITIVITY, SIBLINGS_LIMIT, DENSITY, NODES_QTY, ANCHOR_LENGTH, MOUSE_RADIUS, + TURBULENCE, MOUSE_MOVING_TURBULENCE, MOUSE_ANGLE_TURBULENCE, MOUSE_MOVING_RADIUS, BASE_BRIGHTNESS, RADIUS_DEGRADE, + SAMPLE_SIZE + + let handle + + // how close next node must be to activate connection (in px) + // shorter distance == better connection (line width) + SENSITIVITY = 200 + // note that siblings limit is not 'accurate' as the node can actually have more connections than this value that's because the node accepts sibling nodes with no regard to their current connections this is acceptable because potential fix would not result in significant visual difference + // more siblings == bigger node + SIBLINGS_LIMIT = 10 + // default node margin + DENSITY = 100 + // total number of nodes used (incremented after creation) + NODES_QTY = 0 + // avoid nodes spreading + ANCHOR_LENGTH = 100 + // highlight radius + MOUSE_RADIUS = 200 + // turbulence of randomness + TURBULENCE = 3 + // turbulence of mouse moving + MOUSE_MOVING_TURBULENCE = 50 + // turbulence of mouse moving angle + MOUSE_ANGLE_TURBULENCE = 0.002 + // moving radius of mouse + MOUSE_MOVING_RADIUS = 600 + // base brightness + BASE_BRIGHTNESS = 0.12 + // radius degrade + RADIUS_DEGRADE = 0.4 + // sample size + SAMPLE_SIZE = 0.5 + + circ = 2 * Math.PI + nodes = [] + + canvas = document.querySelector('canvas') + resizeWindow() + ctx = canvas.getContext('2d') + if (!ctx) { + alert('Ooops! Your browser does not support canvas :\'(') + } + + function Mouse(x, y) { + this.anchorX = x + this.anchorY = y + this.x = x + this.y = y - MOUSE_RADIUS / 2 + this.angle = 0 + } + + Mouse.prototype.computePosition = function () { + // this.x = this.anchorX + MOUSE_MOVING_RADIUS / 2 * Math.sin(this.angle) + // this.y = this.anchorY - MOUSE_MOVING_RADIUS / 2 * Math.cos(this.angle) + } + + Mouse.prototype.move = function () { + let vx = Math.random() * MOUSE_MOVING_TURBULENCE + let vy = Math.random() * MOUSE_MOVING_TURBULENCE + if (this.x + vx + MOUSE_RADIUS / 2 > window.innerWidth || this.x + vx - MOUSE_RADIUS / 2 < 0) { + vx = -vx + } + if (this.y + vy + MOUSE_RADIUS / 2 > window.innerHeight || this.y + vy - MOUSE_RADIUS / 2 < 0) { + vy = -vy + } + this.x += vx + this.y += vy + // this.angle += Math.random() * MOUSE_ANGLE_TURBULENCE * 2 * Math.PI + // this.angle -= Math.floor(this.angle / (2 * Math.PI)) * 2 * Math.PI + // this.computePosition() + } + + function Node(x, y) { + this.anchorX = x + this.anchorY = y + this.x = Math.random() * (x - (x - ANCHOR_LENGTH)) + (x - ANCHOR_LENGTH) + this.y = Math.random() * (y - (y - ANCHOR_LENGTH)) + (y - ANCHOR_LENGTH) + this.vx = Math.random() * TURBULENCE - 1 + this.vy = Math.random() * TURBULENCE - 1 + this.energy = Math.random() * 100 + this.radius = Math.random() + this.siblings = [] + this.brightness = 0 + } + + Node.prototype.drawNode = function () { + let color = 'rgba(64, 156, 255, ' + this.brightness + ')' + ctx.beginPath() + ctx.arc(this.x, this.y, 2 * this.radius + 2 * this.siblings.length / SIBLINGS_LIMIT / 1.5, 0, circ) + ctx.fillStyle = color + ctx.fill() + } + + Node.prototype.drawConnections = function () { + for (let i = 0; i < this.siblings.length; i++) { + let color = 'rgba(64, 156, 255, ' + this.brightness + ')' + ctx.beginPath() + ctx.moveTo(this.x, this.y) + ctx.lineTo(this.siblings[i].x, this.siblings[i].y) + ctx.lineWidth = 1 - calcDistance(this, this.siblings[i]) / SENSITIVITY + ctx.strokeStyle = color + ctx.stroke() + } + } + + Node.prototype.moveNode = function () { + this.energy -= 2 + if (this.energy < 1) { + this.energy = Math.random() * 100 + if (this.x - this.anchorX < -ANCHOR_LENGTH) { + this.vx = Math.random() * TURBULENCE + } else if (this.x - this.anchorX > ANCHOR_LENGTH) { + this.vx = Math.random() * -TURBULENCE + } else { + this.vx = Math.random() * 2 * TURBULENCE - TURBULENCE + } + if (this.y - this.anchorY < -ANCHOR_LENGTH) { + this.vy = Math.random() * TURBULENCE + } else if (this.y - this.anchorY > ANCHOR_LENGTH) { + this.vy = Math.random() * -TURBULENCE + } else { + this.vy = Math.random() * 2 * TURBULENCE - TURBULENCE + } + } + this.x += this.vx * this.energy / 100 + this.y += this.vy * this.energy / 100 + } + + function Handle() { + this.isStopped = false + } + + Handle.prototype.stop = function () { + this.isStopped = true + } + + function initNodes() { + ctx.clearRect(0, 0, canvas.width, canvas.height) + nodes = [] + for (let i = DENSITY; i < canvas.width; i += DENSITY) { + for (let j = DENSITY; j < canvas.height; j += DENSITY) { + nodes.push(new Node(i, j)) + NODES_QTY++ + } + } + } + + function initMouse() { + mouse = new Mouse(canvas.width / 2, canvas.height / 2) + } + + function initHandle() { + handle = new Handle() + } + + function calcDistance(node1, node2) { + return Math.sqrt(Math.pow(node1.x - node2.x, 2) + (Math.pow(node1.y - node2.y, 2))) + } + + function findSiblings() { + let node1, node2, distance + for (let i = 0; i < NODES_QTY; i++) { + node1 = nodes[i] + node1.siblings = [] + for (let j = 0; j < NODES_QTY; j++) { + node2 = nodes[j] + if (node1 !== node2) { + distance = calcDistance(node1, node2) + if (distance < SENSITIVITY) { + if (node1.siblings.length < SIBLINGS_LIMIT) { + node1.siblings.push(node2) + } else { + let node_sibling_distance = 0 + let max_distance = 0 + let s + for (let k = 0; k < SIBLINGS_LIMIT; k++) { + node_sibling_distance = calcDistance(node1, node1.siblings[k]) + if (node_sibling_distance > max_distance) { + max_distance = node_sibling_distance + s = k + } + } + if (distance < max_distance) { + node1.siblings.splice(s, 1) + node1.siblings.push(node2) + } + } + } + } + } + } + } + + function redrawScene() { + if (handle && handle.isStopped) { + return + } + resizeWindow() + ctx.clearRect(0, 0, canvas.width, canvas.height) + findSiblings() + let i, node, distance + for (i = 0; i < NODES_QTY; i++) { + node = nodes[i] + distance = calcDistance({ + x: mouse.x, + y: mouse.y + }, node) + node.brightness = (1 - Math.log(distance / MOUSE_RADIUS * RADIUS_DEGRADE)) * BASE_BRIGHTNESS + } + for (i = 0; i < NODES_QTY; i++) { + node = nodes[i] + if (node.brightness) { + node.drawNode() + node.drawConnections() + } + node.moveNode() + } + // mouse.move() + setTimeout(() => { + requestAnimationFrame(redrawScene) + }, 50) + } + + function initHandlers() { + document.addEventListener('resize', resizeWindow, false) + // canvas.addEventListener('mousemove', mousemoveHandler, false) + } + + function resizeWindow() { + canvas.width = window.innerWidth + canvas.height = window.innerHeight + } + + function mousemoveHandler(e) { + mouse.x = e.clientX + mouse.y = e.clientY + } + + function init() { + initHandlers() + initNodes() + initMouse() + initHandle() + redrawScene() + } + + function reset() { + handle.isStopped = true + } + + init() + + window.resetCanvas = reset +} + +(function () { + window.initCanvas = initCanvas + window.initCanvas() +}()) diff --git a/frontend/src/assets/logo.svg b/frontend/src/assets/logo.svg index 9a6d69ac..c52872b4 100644 --- a/frontend/src/assets/logo.svg +++ b/frontend/src/assets/logo.svg @@ -1,14 +1,16 @@ - - - - - - - - + + + + + + + + + + diff --git a/frontend/src/components/Breadcrumb/index.vue b/frontend/src/components/Breadcrumb/index.vue deleted file mode 100644 index 241c81a3..00000000 --- a/frontend/src/components/Breadcrumb/index.vue +++ /dev/null @@ -1,88 +0,0 @@ - - - - - diff --git a/frontend/src/components/Common/BatchAddScheduleDialog.vue b/frontend/src/components/Common/BatchAddScheduleDialog.vue deleted file mode 100644 index feaa6cc3..00000000 --- a/frontend/src/components/Common/BatchAddScheduleDialog.vue +++ /dev/null @@ -1,315 +0,0 @@ - - - - - diff --git a/frontend/src/components/Common/BatchCrawlDialog.vue b/frontend/src/components/Common/BatchCrawlDialog.vue deleted file mode 100644 index 09b24589..00000000 --- a/frontend/src/components/Common/BatchCrawlDialog.vue +++ /dev/null @@ -1,285 +0,0 @@ - - - - - diff --git a/frontend/src/components/Common/CrawlConfirmDialog.vue b/frontend/src/components/Common/CrawlConfirmDialog.vue deleted file mode 100644 index 14f86e73..00000000 --- a/frontend/src/components/Common/CrawlConfirmDialog.vue +++ /dev/null @@ -1,362 +0,0 @@ - - - - - diff --git a/frontend/src/components/Common/ParametersDialog.vue b/frontend/src/components/Common/ParametersDialog.vue deleted file mode 100644 index 4c138ed2..00000000 --- a/frontend/src/components/Common/ParametersDialog.vue +++ /dev/null @@ -1,220 +0,0 @@ - - - - - diff --git a/frontend/src/components/Config/ConfigList.vue b/frontend/src/components/Config/ConfigList.vue deleted file mode 100644 index 98745277..00000000 --- a/frontend/src/components/Config/ConfigList.vue +++ /dev/null @@ -1,1259 +0,0 @@ - - - - - diff --git a/frontend/src/components/Cron/index.vue b/frontend/src/components/Cron/index.vue deleted file mode 100644 index 0bc29d10..00000000 --- a/frontend/src/components/Cron/index.vue +++ /dev/null @@ -1,465 +0,0 @@ - - - diff --git a/frontend/src/components/Cron/language/cn.js b/frontend/src/components/Cron/language/cn.js deleted file mode 100644 index 7c6df9f7..00000000 --- a/frontend/src/components/Cron/language/cn.js +++ /dev/null @@ -1,61 +0,0 @@ -export default { - Seconds: { - name: '秒', - every: '每一秒钟', - interval: ['每隔', '秒执行 从', '秒开始'], - specific: '具体秒数(可多选)', - cycle: ['周期从', '到', '秒'] - }, - Minutes: { - name: '分', - every: '每一分钟', - interval: ['每隔', '分执行 从', '分开始'], - specific: '具体分钟数(可多选)', - cycle: ['周期从', '到', '分'] - }, - Hours: { - name: '时', - every: '每一小时', - interval: ['每隔', '小时执行 从', '小时开始'], - specific: '具体小时数(可多选)', - cycle: ['周期从', '到', '小时'] - }, - Day: { - name: '天', - every: '每一天', - intervalWeek: ['每隔', '周执行 从', '开始'], - intervalDay: ['每隔', '天执行 从', '天开始'], - specificWeek: '具体星期几(可多选)', - specificDay: '具体天数(可多选)', - lastDay: '在这个月的最后一天', - lastWeekday: '在这个月的最后一个工作日', - lastWeek: ['在这个月的最后一个'], - beforeEndMonth: ['在本月底前', '天'], - nearestWeekday: ['最近的工作日(周一至周五)至本月', '日'], - someWeekday: ['在这个月的第', '个'], - cycle: ['从', '到'] - }, - Week: { - name: '周', - every: '每天', - specific: '具体天数(可多选)', - list: ['一', '二', '三', '四', '五', '六', '天'].map(val => '星期' + val), - cycle: ['从', '到'] - }, - Month: { - name: '月', - every: '每一月', - interval: ['每隔', '月执行 从', '月开始'], - specific: '具体月数(可多选)', - cycle: ['从', '到', '月之间的每个月'] - }, - Year: { - name: '年', - every: '每一年', - interval: ['每隔', '年执行 从', '年开始'], - specific: '具体年份(可多选)', - cycle: ['从', '到', '年之间的每一年'] - }, - Save: '保存', - Close: '关闭' -} diff --git a/frontend/src/components/Cron/language/en.js b/frontend/src/components/Cron/language/en.js deleted file mode 100644 index fdcafa02..00000000 --- a/frontend/src/components/Cron/language/en.js +++ /dev/null @@ -1,71 +0,0 @@ -export default { - Seconds: { - name: 'Seconds', - every: 'Every second', - interval: ['Every', 'second(s) starting at second'], - specific: 'Specific second (choose one or many)', - cycle: ['Every second between second', 'and second'] - }, - Minutes: { - name: 'Minutes', - every: 'Every minute', - interval: ['Every', 'minute(s) starting at minute'], - specific: 'Specific minute (choose one or many)', - cycle: ['Every minute between minute', 'and minute'] - }, - Hours: { - name: 'Hours', - every: 'Every hour', - interval: ['Every', 'hour(s) starting at hour'], - specific: 'Specific hour (choose one or many)', - cycle: ['Every hour between hour', 'and hour'] - }, - Day: { - name: 'Day', - every: 'Every day', - intervalWeek: ['Every', 'day(s) starting on'], - intervalDay: ['Every', 'day(s) starting at the', 'of the month'], - specificWeek: 'Specific day of week (choose one or many)', - specificDay: 'Specific day of month (choose one or many)', - lastDay: 'On the last day of the month', - lastWeekday: 'On the last weekday of the month', - lastWeek: ['On the last', ' of the month'], - beforeEndMonth: ['day(s) before the end of the month'], - nearestWeekday: [ - 'Nearest weekday (Monday to Friday) to the', - 'of the month'], - someWeekday: ['On the', 'of the month'], - cycle: ['From', 'to'] - }, - Week: { - name: 'Week', - every: 'Every day', - specific: 'Specific weekday (choose on or many)', - list: [ - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday', - 'Sunday'], - cycle: ['From', 'to'] - }, - // Week:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], - Month: { - name: 'Month', - every: 'Every month', - interval: ['Every', 'month(s) starting in'], - specific: 'Specific month (choose one or many)', - cycle: ['Every month between', 'and'] - }, - Year: { - name: 'Year', - every: 'Any year', - interval: ['Every', 'year(s) starting in'], - specific: 'Specific year (choose one or many)', - cycle: ['Every year between', 'and'] - }, - Save: 'Save', - Close: 'Close' -} diff --git a/frontend/src/components/Cron/language/index.js b/frontend/src/components/Cron/language/index.js deleted file mode 100644 index 1e592c13..00000000 --- a/frontend/src/components/Cron/language/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import en from './en' -import cn from './cn' - -export default { - en, - cn -} diff --git a/frontend/src/components/Documentation/Documentation.vue b/frontend/src/components/Documentation/Documentation.vue deleted file mode 100644 index 2fc494fd..00000000 --- a/frontend/src/components/Documentation/Documentation.vue +++ /dev/null @@ -1,117 +0,0 @@ - - - - diff --git a/frontend/src/components/Environment/EnvironmentList.vue b/frontend/src/components/Environment/EnvironmentList.vue deleted file mode 100644 index 9ed0fd03..00000000 --- a/frontend/src/components/Environment/EnvironmentList.vue +++ /dev/null @@ -1,81 +0,0 @@ - - - - - diff --git a/frontend/src/components/File/FileDetail.vue b/frontend/src/components/File/FileDetail.vue deleted file mode 100644 index 3334f7ff..00000000 --- a/frontend/src/components/File/FileDetail.vue +++ /dev/null @@ -1,105 +0,0 @@ - - - - - diff --git a/frontend/src/components/File/FileEditor.vue b/frontend/src/components/File/FileEditor.vue new file mode 100644 index 00000000..e58d5d81 --- /dev/null +++ b/frontend/src/components/File/FileEditor.vue @@ -0,0 +1,823 @@ + + + + + + diff --git a/frontend/src/components/File/FileEditorNavMenu.vue b/frontend/src/components/File/FileEditorNavMenu.vue new file mode 100644 index 00000000..2d9774a2 --- /dev/null +++ b/frontend/src/components/File/FileEditorNavMenu.vue @@ -0,0 +1,479 @@ + + + + + + diff --git a/frontend/src/components/File/FileEditorNavMenuContextMenu.vue b/frontend/src/components/File/FileEditorNavMenuContextMenu.vue new file mode 100644 index 00000000..8e5dacea --- /dev/null +++ b/frontend/src/components/File/FileEditorNavMenuContextMenu.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/frontend/src/components/File/FileEditorNavTabs.vue b/frontend/src/components/File/FileEditorNavTabs.vue new file mode 100644 index 00000000..305a41bd --- /dev/null +++ b/frontend/src/components/File/FileEditorNavTabs.vue @@ -0,0 +1,271 @@ + + + + + diff --git a/frontend/src/components/File/FileEditorNavTabsContextMenu.vue b/frontend/src/components/File/FileEditorNavTabsContextMenu.vue new file mode 100644 index 00000000..7f2d0204 --- /dev/null +++ b/frontend/src/components/File/FileEditorNavTabsContextMenu.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/frontend/src/components/File/FileEditorNavTabsShowMoreContextMenu.vue b/frontend/src/components/File/FileEditorNavTabsShowMoreContextMenu.vue new file mode 100644 index 00000000..7a04fa6e --- /dev/null +++ b/frontend/src/components/File/FileEditorNavTabsShowMoreContextMenu.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/frontend/src/components/File/FileEditorSettingsDialog.vue b/frontend/src/components/File/FileEditorSettingsDialog.vue new file mode 100644 index 00000000..9b12976e --- /dev/null +++ b/frontend/src/components/File/FileEditorSettingsDialog.vue @@ -0,0 +1,198 @@ + + + + + + + + diff --git a/frontend/src/components/File/FileEditorSettingsFormItem.vue b/frontend/src/components/File/FileEditorSettingsFormItem.vue new file mode 100644 index 00000000..f8e7d4ef --- /dev/null +++ b/frontend/src/components/File/FileEditorSettingsFormItem.vue @@ -0,0 +1,50 @@ + + + diff --git a/frontend/src/components/File/FileList.vue b/frontend/src/components/File/FileList.vue deleted file mode 100644 index 4ad29fa5..00000000 --- a/frontend/src/components/File/FileList.vue +++ /dev/null @@ -1,679 +0,0 @@ - - - - - - - - - diff --git a/frontend/src/components/File/fileEditorDropZone.ts b/frontend/src/components/File/fileEditorDropZone.ts new file mode 100644 index 00000000..e276287e --- /dev/null +++ b/frontend/src/components/File/fileEditorDropZone.ts @@ -0,0 +1,23 @@ +import {useDropzone} from 'vue3-dropzone'; + +const useFileEditorDropZone = () => { + const onDrop = (acceptedFiles: InputFile[], rejectReasons: FileRejectReason[], event: Event) => { + console.log(acceptedFiles); + }; + + const { + getRootProps, + getInputProps, + open, + } = useDropzone({ + onDrop, + }); + + return { + getRootProps, + getInputProps, + open, + }; +}; + +export default useFileEditorDropZone; diff --git a/frontend/src/components/Hamburger/index.vue b/frontend/src/components/Hamburger/index.vue deleted file mode 100644 index 0a6c371f..00000000 --- a/frontend/src/components/Hamburger/index.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - - - diff --git a/frontend/src/components/InfoView/NodeInfoView.vue b/frontend/src/components/InfoView/NodeInfoView.vue deleted file mode 100644 index f20cda15..00000000 --- a/frontend/src/components/InfoView/NodeInfoView.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - - - diff --git a/frontend/src/components/InfoView/SpiderInfoView.vue b/frontend/src/components/InfoView/SpiderInfoView.vue deleted file mode 100644 index 13289fe0..00000000 --- a/frontend/src/components/InfoView/SpiderInfoView.vue +++ /dev/null @@ -1,361 +0,0 @@ - - - - - diff --git a/frontend/src/components/InfoView/TaskInfoView.vue b/frontend/src/components/InfoView/TaskInfoView.vue deleted file mode 100644 index c3a45d96..00000000 --- a/frontend/src/components/InfoView/TaskInfoView.vue +++ /dev/null @@ -1,181 +0,0 @@ - - - - - diff --git a/frontend/src/components/Node/CreateEditNodeDialog.vue b/frontend/src/components/Node/CreateEditNodeDialog.vue new file mode 100644 index 00000000..d0a0cfee --- /dev/null +++ b/frontend/src/components/Node/CreateEditNodeDialog.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/frontend/src/components/Node/NodeActive.vue b/frontend/src/components/Node/NodeActive.vue new file mode 100644 index 00000000..a094a84e --- /dev/null +++ b/frontend/src/components/Node/NodeActive.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/frontend/src/components/Node/NodeForm.vue b/frontend/src/components/Node/NodeForm.vue new file mode 100644 index 00000000..a0f91927 --- /dev/null +++ b/frontend/src/components/Node/NodeForm.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/frontend/src/components/Node/NodeInstallation.vue b/frontend/src/components/Node/NodeInstallation.vue deleted file mode 100644 index a9dcf7c6..00000000 --- a/frontend/src/components/Node/NodeInstallation.vue +++ /dev/null @@ -1,354 +0,0 @@ - - - - - diff --git a/frontend/src/components/Node/NodeInstallationMatrix.vue b/frontend/src/components/Node/NodeInstallationMatrix.vue deleted file mode 100644 index 0951d53e..00000000 --- a/frontend/src/components/Node/NodeInstallationMatrix.vue +++ /dev/null @@ -1,573 +0,0 @@ - - - - - diff --git a/frontend/src/components/Node/NodeNetwork.vue b/frontend/src/components/Node/NodeNetwork.vue deleted file mode 100644 index 344e1d81..00000000 --- a/frontend/src/components/Node/NodeNetwork.vue +++ /dev/null @@ -1,190 +0,0 @@ - - - - - diff --git a/frontend/src/components/Node/NodeRunners.vue b/frontend/src/components/Node/NodeRunners.vue new file mode 100644 index 00000000..f53f5bf2 --- /dev/null +++ b/frontend/src/components/Node/NodeRunners.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/frontend/src/components/Node/NodeStatus.vue b/frontend/src/components/Node/NodeStatus.vue new file mode 100644 index 00000000..ad04c71e --- /dev/null +++ b/frontend/src/components/Node/NodeStatus.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/frontend/src/components/Node/NodeType.vue b/frontend/src/components/Node/NodeType.vue new file mode 100644 index 00000000..50eac397 --- /dev/null +++ b/frontend/src/components/Node/NodeType.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/frontend/src/components/Node/node.ts b/frontend/src/components/Node/node.ts new file mode 100644 index 00000000..f0ab1358 --- /dev/null +++ b/frontend/src/components/Node/node.ts @@ -0,0 +1,61 @@ +import {readonly} from 'vue'; +import {Store} from 'vuex'; +import useForm from '@/components/form/form'; +import useNodeService from '@/services/node/nodeService'; +import {getDefaultFormComponentData} from '@/utils/form'; +import {FORM_FIELD_TYPE_INPUT, FORM_FIELD_TYPE_INPUT_TEXTAREA, FORM_FIELD_TYPE_SWITCH} from '@/constants/form'; + +type Node = CNode; + +// get new node +export const getNewNode = (): Node => { + return { + tags: [], + max_runners: 8, + enabled: true, + }; +}; + +// form component data +const formComponentData = getDefaultFormComponentData(getNewNode); + +const useNode = (store: Store) => { + // store + const ns = 'node'; + const {node: state} = store.state as RootStoreState; + + // batch form fields + const batchFormFields: FormTableField[] = [ + { + prop: 'name', + label: 'Name', + width: '150', + fieldType: FORM_FIELD_TYPE_INPUT, + required: true, + placeholder: 'Name', + }, + { + prop: 'enabled', + label: 'Enabled', + width: '120', + fieldType: FORM_FIELD_TYPE_SWITCH, + }, + { + prop: 'description', + label: 'Description', + width: '200', + fieldType: FORM_FIELD_TYPE_INPUT_TEXTAREA, + }, + ]; + + // form rules + const formRules = readonly({}); + + return { + ...useForm(ns, store, useNodeService(store), formComponentData), + batchFormFields, + formRules, + }; +}; + +export default useNode; diff --git a/frontend/src/components/Overview/NodeOverview.vue b/frontend/src/components/Overview/NodeOverview.vue deleted file mode 100644 index bb5399fd..00000000 --- a/frontend/src/components/Overview/NodeOverview.vue +++ /dev/null @@ -1,50 +0,0 @@ - - - - - diff --git a/frontend/src/components/Overview/SpiderOverview.vue b/frontend/src/components/Overview/SpiderOverview.vue deleted file mode 100644 index e4606cac..00000000 --- a/frontend/src/components/Overview/SpiderOverview.vue +++ /dev/null @@ -1,56 +0,0 @@ - - - - - diff --git a/frontend/src/components/Overview/TaskOverview.vue b/frontend/src/components/Overview/TaskOverview.vue deleted file mode 100644 index 1b77f717..00000000 --- a/frontend/src/components/Overview/TaskOverview.vue +++ /dev/null @@ -1,134 +0,0 @@ - - - - - diff --git a/frontend/src/components/Pagination/index.vue b/frontend/src/components/Pagination/index.vue deleted file mode 100644 index cc83c6d5..00000000 --- a/frontend/src/components/Pagination/index.vue +++ /dev/null @@ -1,101 +0,0 @@ - - - - - diff --git a/frontend/src/components/PanThumb/index.vue b/frontend/src/components/PanThumb/index.vue deleted file mode 100644 index 5b984c11..00000000 --- a/frontend/src/components/PanThumb/index.vue +++ /dev/null @@ -1,140 +0,0 @@ - - - - - diff --git a/frontend/src/components/Schedule/CreateEditScheduleDialog.vue b/frontend/src/components/Schedule/CreateEditScheduleDialog.vue new file mode 100644 index 00000000..115a1733 --- /dev/null +++ b/frontend/src/components/Schedule/CreateEditScheduleDialog.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/frontend/src/components/Schedule/ScheduleCron.vue b/frontend/src/components/Schedule/ScheduleCron.vue new file mode 100644 index 00000000..54690371 --- /dev/null +++ b/frontend/src/components/Schedule/ScheduleCron.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/frontend/src/components/Schedule/ScheduleForm.vue b/frontend/src/components/Schedule/ScheduleForm.vue new file mode 100644 index 00000000..3cc8c564 --- /dev/null +++ b/frontend/src/components/Schedule/ScheduleForm.vue @@ -0,0 +1,193 @@ + + + + + diff --git a/frontend/src/components/Schedule/ScheduleTaskList.vue b/frontend/src/components/Schedule/ScheduleTaskList.vue deleted file mode 100644 index ff963a86..00000000 --- a/frontend/src/components/Schedule/ScheduleTaskList.vue +++ /dev/null @@ -1,30 +0,0 @@ - diff --git a/frontend/src/components/Schedule/schedule.ts b/frontend/src/components/Schedule/schedule.ts new file mode 100644 index 00000000..86911322 --- /dev/null +++ b/frontend/src/components/Schedule/schedule.ts @@ -0,0 +1,153 @@ +import {computed, readonly, watch} from 'vue'; +import {Store} from 'vuex'; +import useForm from '@/components/form/form'; +import useScheduleService from '@/services/schedule/scheduleService'; +import {getDefaultFormComponentData} from '@/utils/form'; +import { + FORM_FIELD_TYPE_INPUT, + FORM_FIELD_TYPE_INPUT_WITH_BUTTON, + FORM_FIELD_TYPE_SELECT, + FORM_FIELD_TYPE_SWITCH, +} from '@/constants/form'; +import {parseExpression} from 'cron-parser'; +import {getModeOptions} from '@/utils/task'; +import useSpider from '@/components/spider/spider'; +import {TASK_MODE_RANDOM} from '@/constants/task'; + +// get new schedule +export const getNewSchedule = (): Schedule => { + return { + enabled: true, + mode: TASK_MODE_RANDOM, + }; +}; + +// form component data +const formComponentData = getDefaultFormComponentData(getNewSchedule); + +const useSchedule = (store: Store) => { + // store + const ns = 'schedule'; + const state = store.state[ns]; + + const { + allListSelectOptions: allSpiderListSelectOptions, + allDict: allSpiderDict, + } = useSpider(store); + // form + const form = computed(() => state.form); + + // options for default mode + const modeOptions = getModeOptions(); + + // readonly form fields + const readonlyFormFields = computed(() => state.readonlyFormFields); + + // batch form fields + const batchFormFields = computed(() => [ + { + prop: 'name', + label: 'Name', + width: '150', + fieldType: FORM_FIELD_TYPE_INPUT, + placeholder: 'Name', + required: true, + }, + { + prop: 'spider_id', + label: 'Spider', + width: '150', + placeholder: 'Spider', + fieldType: FORM_FIELD_TYPE_SELECT, + options: allSpiderListSelectOptions.value, + disabled: () => readonlyFormFields.value.includes('spider_id'), + required: true, + }, + { + prop: 'cron', + label: 'Cron Expression', + width: '150', + fieldType: FORM_FIELD_TYPE_INPUT, + placeholder: 'Name', + required: true, + }, + { + prop: 'cmd', + label: 'Execute Command', + width: '200', + placeholder: 'Execute Command', + fieldType: FORM_FIELD_TYPE_INPUT_WITH_BUTTON, + }, + { + prop: 'param', + label: 'Param', + width: '200', + placeholder: 'Param', + fieldType: FORM_FIELD_TYPE_INPUT_WITH_BUTTON, + }, + { + prop: 'mode', + label: 'Default Run Mode', + width: '200', + fieldType: FORM_FIELD_TYPE_SELECT, + options: modeOptions, + required: true, + }, + { + prop: 'enabled', + label: 'Enabled', + width: '80', + fieldType: FORM_FIELD_TYPE_SWITCH, + required: true, + }, + ]); + + // form rules + const formRules = readonly({ + cron: { + trigger: 'blur', + validator: ((_, value: string, callback) => { + const invalidMessage = 'Invalid cron expression. [min] [hour] [day of month] [month] [day of week]'; + if (!value) return callback(invalidMessage); + if (value.trim().split(' ').length != 5) return callback(invalidMessage); + try { + parseExpression(value); + callback(); + } catch (e) { + callback(e.message); + } + }), + }, + }); + + // all schedule select options + const allScheduleSelectOptions = computed(() => state.allList.map(d => { + return { + label: d.name, + value: d._id, + }; + })); + + watch(() => form.value?.spider_id, () => { + if (!form.value?.spider_id) return; + const spider = allSpiderDict.value.get(form.value?.spider_id); + if (!spider) return; + const payload = {...form.value} as Schedule; + if (spider.cmd) payload.cmd = spider.cmd; + if (spider.param) payload.param = spider.param; + if (spider.mode) payload.mode = spider.mode; + if (spider.node_ids?.length) payload.node_ids = spider.node_ids; + if (spider.node_tags?.length) payload.node_tags = spider.node_tags; + store.commit(`${ns}/setForm`, payload); + }); + + return { + ...useForm('schedule', store, useScheduleService(store), formComponentData), + modeOptions, + batchFormFields, + formRules, + allScheduleSelectOptions, + }; +}; + +export default useSchedule; diff --git a/frontend/src/components/Scrapy/SpiderScrapy.vue b/frontend/src/components/Scrapy/SpiderScrapy.vue deleted file mode 100644 index 4abc6a32..00000000 --- a/frontend/src/components/Scrapy/SpiderScrapy.vue +++ /dev/null @@ -1,846 +0,0 @@ - - - - - - diff --git a/frontend/src/components/Screenfull/index.vue b/frontend/src/components/Screenfull/index.vue deleted file mode 100644 index 6247b516..00000000 --- a/frontend/src/components/Screenfull/index.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - - - diff --git a/frontend/src/components/ScrollPane/index.vue b/frontend/src/components/ScrollPane/index.vue deleted file mode 100644 index 72d2b452..00000000 --- a/frontend/src/components/ScrollPane/index.vue +++ /dev/null @@ -1,81 +0,0 @@ - - - - - diff --git a/frontend/src/components/ScrollView/LogItem.vue b/frontend/src/components/ScrollView/LogItem.vue deleted file mode 100644 index bc09a6fb..00000000 --- a/frontend/src/components/ScrollView/LogItem.vue +++ /dev/null @@ -1,121 +0,0 @@ - - - - - diff --git a/frontend/src/components/ScrollView/LogView.vue b/frontend/src/components/ScrollView/LogView.vue deleted file mode 100644 index d77ffc51..00000000 --- a/frontend/src/components/ScrollView/LogView.vue +++ /dev/null @@ -1,377 +0,0 @@ - - - - - diff --git a/frontend/src/components/Settings/GitSettings.vue b/frontend/src/components/Settings/GitSettings.vue deleted file mode 100644 index 98b87ded..00000000 --- a/frontend/src/components/Settings/GitSettings.vue +++ /dev/null @@ -1,480 +0,0 @@ - - - - - diff --git a/frontend/src/components/Share/dropdownMenu.vue b/frontend/src/components/Share/dropdownMenu.vue deleted file mode 100644 index 3ad3c396..00000000 --- a/frontend/src/components/Share/dropdownMenu.vue +++ /dev/null @@ -1,100 +0,0 @@ - - - - - diff --git a/frontend/src/components/SizeSelect/index.vue b/frontend/src/components/SizeSelect/index.vue deleted file mode 100644 index 937e2963..00000000 --- a/frontend/src/components/SizeSelect/index.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - diff --git a/frontend/src/components/Spider/CopySpiderDialog.vue b/frontend/src/components/Spider/CopySpiderDialog.vue deleted file mode 100644 index 75fc270f..00000000 --- a/frontend/src/components/Spider/CopySpiderDialog.vue +++ /dev/null @@ -1,85 +0,0 @@ - - - - - diff --git a/frontend/src/components/Spider/CreateEditSpiderDialog.vue b/frontend/src/components/Spider/CreateEditSpiderDialog.vue new file mode 100644 index 00000000..3d38bfdf --- /dev/null +++ b/frontend/src/components/Spider/CreateEditSpiderDialog.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/frontend/src/components/Spider/RunSpiderDialog.vue b/frontend/src/components/Spider/RunSpiderDialog.vue new file mode 100644 index 00000000..1f084afb --- /dev/null +++ b/frontend/src/components/Spider/RunSpiderDialog.vue @@ -0,0 +1,186 @@ + + + + + diff --git a/frontend/src/components/Spider/SpiderForm.vue b/frontend/src/components/Spider/SpiderForm.vue new file mode 100644 index 00000000..6fc9f5b1 --- /dev/null +++ b/frontend/src/components/Spider/SpiderForm.vue @@ -0,0 +1,198 @@ + + + + + diff --git a/frontend/src/components/Spider/SpiderStat.vue b/frontend/src/components/Spider/SpiderStat.vue new file mode 100644 index 00000000..8ed22b5b --- /dev/null +++ b/frontend/src/components/Spider/SpiderStat.vue @@ -0,0 +1,100 @@ + + + + + + + diff --git a/frontend/src/components/Spider/SpiderTag.vue b/frontend/src/components/Spider/SpiderTag.vue new file mode 100644 index 00000000..a756f7fc --- /dev/null +++ b/frontend/src/components/Spider/SpiderTag.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/frontend/src/components/Spider/SpiderType.vue b/frontend/src/components/Spider/SpiderType.vue new file mode 100644 index 00000000..c574ac70 --- /dev/null +++ b/frontend/src/components/Spider/SpiderType.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/frontend/src/components/Spider/spider.ts b/frontend/src/components/Spider/spider.ts new file mode 100644 index 00000000..a99a55a1 --- /dev/null +++ b/frontend/src/components/Spider/spider.ts @@ -0,0 +1,130 @@ +import {useRoute} from 'vue-router'; +import {computed} from 'vue'; +import {TASK_MODE_RANDOM} from '@/constants/task'; +import {Store} from 'vuex'; +import useForm from '@/components/form/form'; +import useSpiderService from '@/services/spider/spiderService'; +import {getDefaultFormComponentData} from '@/utils/form'; +import { + FORM_FIELD_TYPE_INPUT, + FORM_FIELD_TYPE_INPUT_TEXTAREA, + FORM_FIELD_TYPE_INPUT_WITH_BUTTON, + FORM_FIELD_TYPE_SELECT +} from '@/constants/form'; +import useProject from '@/components/project/project'; +import useRequest from '@/services/request'; +import {FILTER_OP_CONTAINS} from '@/constants/filter'; +import {getModeOptions} from '@/utils/task'; + +const { + getList, +} = useRequest(); + +// get new spider +export const getNewSpider = (): Spider => { + return { + mode: TASK_MODE_RANDOM, + }; +}; + +// form component data +const formComponentData = getDefaultFormComponentData(getNewSpider); + +const useSpider = (store: Store) => { + // options for default mode + const modeOptions = getModeOptions(); + + // use project + const { + allProjectSelectOptions, + } = useProject(store); + + // batch form fields + const batchFormFields = computed(() => [ + { + prop: 'name', + label: 'Name', + width: '150', + placeholder: 'Spider Name', + fieldType: FORM_FIELD_TYPE_INPUT, + required: true, + }, + { + prop: 'cmd', + label: 'Execute Command', + width: '200', + placeholder: 'Execute Command', + fieldType: FORM_FIELD_TYPE_INPUT_WITH_BUTTON, + required: true, + }, + { + prop: 'param', + label: 'Param', + width: '200', + placeholder: 'Param', + fieldType: FORM_FIELD_TYPE_INPUT_WITH_BUTTON, + }, + { + prop: 'mode', + label: 'Default Run Mode', + width: '200', + fieldType: FORM_FIELD_TYPE_SELECT, + options: modeOptions, + required: true, + }, + { + prop: 'project_id', + label: 'Project', + width: '200', + fieldType: FORM_FIELD_TYPE_SELECT, + options: allProjectSelectOptions.value, + }, + { + prop: 'description', + label: 'Description', + width: '200', + fieldType: FORM_FIELD_TYPE_INPUT_TEXTAREA, + }, + ]); + + // route + const route = useRoute(); + + // spider id + const id = computed(() => route.params.id); + + // fetch data collections + const fetchDataCollection = async (query: string) => { + const conditions = [{ + key: 'name', + op: FILTER_OP_CONTAINS, + value: query, + }] as FilterConditionData[]; + const res = await getList(`/data/collections`, {conditions}); + return res.data; + }; + + // fetch data collection suggestions + const fetchDataCollectionSuggestions = (query: string, cb: Function) => { + fetchDataCollection(query) + .then(data => { + cb(data?.map((d: DataCollection) => { + return { + _id: d._id, + value: d.name, + }; + })); + }); + }; + + return { + ...useForm('spider', store, useSpiderService(store), formComponentData), + batchFormFields, + id, + modeOptions, + fetchDataCollection, + fetchDataCollectionSuggestions, + }; +}; + +export default useSpider; diff --git a/frontend/src/components/Stats/MetricCard.vue b/frontend/src/components/Stats/MetricCard.vue deleted file mode 100644 index a86d3ea7..00000000 --- a/frontend/src/components/Stats/MetricCard.vue +++ /dev/null @@ -1,89 +0,0 @@ - - - - - diff --git a/frontend/src/components/Stats/SpiderStats.vue b/frontend/src/components/Stats/SpiderStats.vue deleted file mode 100644 index 20b2bbeb..00000000 --- a/frontend/src/components/Stats/SpiderStats.vue +++ /dev/null @@ -1,197 +0,0 @@ - - - - - diff --git a/frontend/src/components/Status/StatusLegend.vue b/frontend/src/components/Status/StatusLegend.vue deleted file mode 100644 index d15660f1..00000000 --- a/frontend/src/components/Status/StatusLegend.vue +++ /dev/null @@ -1,40 +0,0 @@ - - - - - diff --git a/frontend/src/components/Status/StatusTag.vue b/frontend/src/components/Status/StatusTag.vue deleted file mode 100644 index 645b6c7b..00000000 --- a/frontend/src/components/Status/StatusTag.vue +++ /dev/null @@ -1,67 +0,0 @@ - - - - - diff --git a/frontend/src/components/Sticky/index.vue b/frontend/src/components/Sticky/index.vue deleted file mode 100644 index 822c0ff7..00000000 --- a/frontend/src/components/Sticky/index.vue +++ /dev/null @@ -1,88 +0,0 @@ - - - diff --git a/frontend/src/components/SvgIcon/index.vue b/frontend/src/components/SvgIcon/index.vue deleted file mode 100644 index 585042a1..00000000 --- a/frontend/src/components/SvgIcon/index.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - - - diff --git a/frontend/src/components/TableView/DeployTableView.vue b/frontend/src/components/TableView/DeployTableView.vue deleted file mode 100644 index 7786342f..00000000 --- a/frontend/src/components/TableView/DeployTableView.vue +++ /dev/null @@ -1,76 +0,0 @@ - - - - - diff --git a/frontend/src/components/TableView/FieldsTableView.vue b/frontend/src/components/TableView/FieldsTableView.vue deleted file mode 100644 index 6c9b52e8..00000000 --- a/frontend/src/components/TableView/FieldsTableView.vue +++ /dev/null @@ -1,360 +0,0 @@ - - - - - diff --git a/frontend/src/components/TableView/GeneralTableView.vue b/frontend/src/components/TableView/GeneralTableView.vue deleted file mode 100644 index ce69bfe4..00000000 --- a/frontend/src/components/TableView/GeneralTableView.vue +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - diff --git a/frontend/src/components/TableView/SettingFieldsTableView.vue b/frontend/src/components/TableView/SettingFieldsTableView.vue deleted file mode 100644 index 9d360d47..00000000 --- a/frontend/src/components/TableView/SettingFieldsTableView.vue +++ /dev/null @@ -1,248 +0,0 @@ - - - - - diff --git a/frontend/src/components/TableView/TaskTableView.vue b/frontend/src/components/TableView/TaskTableView.vue deleted file mode 100644 index e4951259..00000000 --- a/frontend/src/components/TableView/TaskTableView.vue +++ /dev/null @@ -1,166 +0,0 @@ - - - - - diff --git a/frontend/src/components/ThemePicker/index.vue b/frontend/src/components/ThemePicker/index.vue deleted file mode 100644 index 72fe15b7..00000000 --- a/frontend/src/components/ThemePicker/index.vue +++ /dev/null @@ -1,149 +0,0 @@ - - - - - diff --git a/frontend/src/components/Tinymce/components/editorImage 2.vue b/frontend/src/components/Tinymce/components/editorImage 2.vue deleted file mode 100644 index 45232050..00000000 --- a/frontend/src/components/Tinymce/components/editorImage 2.vue +++ /dev/null @@ -1,104 +0,0 @@ - - - - - diff --git a/frontend/src/components/Tinymce/components/editorImage.vue b/frontend/src/components/Tinymce/components/editorImage.vue deleted file mode 100644 index 45232050..00000000 --- a/frontend/src/components/Tinymce/components/editorImage.vue +++ /dev/null @@ -1,104 +0,0 @@ - - - - - diff --git a/frontend/src/components/Tinymce/index.vue b/frontend/src/components/Tinymce/index.vue deleted file mode 100644 index 5c0d65ef..00000000 --- a/frontend/src/components/Tinymce/index.vue +++ /dev/null @@ -1,210 +0,0 @@ -